1

I want to configure a Bogus rule that sets a dynamic property on an otherwise straight forward model.

N.B. I'm aware this is very much related to the C# compiler/runtime in general and would very much welcome a solution in that context. However, I would also appreciate a Bogus-specific solution, if there is any.

public class Foo
{
    public string Id { get; set; }
    public dynamic Attributes { get; set; }
}

Using the Bogus library I want to configure a Faker rule, like so:

public static IReadOnlyCollection<Foo> FakeFoos(int amount)
{
    var config = new Faker<Foo>()
        .StrictMode(false)
        .RuleFor(x => x.Id, y => y.Random.Guid().ToString("N"))
        .RuleFor(x => x.Attributes.......)  // <-- this here
    return config.Generate(amount);
}

Let's just say I want to set foo.Attributes.Percentage to an integer. I've tried several ways, all resulting in different errors on dotnetcore 3.1.

Example 1:

// Error [CS1963] An expression tree may not contain a dynamic operation
.RuleFor(x => x.Attributes.Percentage, y => y.Random.Int(70, 90))

Example 2:

// Error System.ArgumentException : Your expression '(x.Attributes As SomeWrappingClass).Percentage' cant be used. 
// Nested accessors like 'o => o.NestedO...
.RuleFor(x => (x.Attributes as SomeWrappingClass).Percentage, y => y.Random.Int(70, 90))

Example 3:

// Error RuntimeBinderException : Cannot perform runtime binding on a null reference
.RuleFor(x => x.Attributes, y => new SomeWrappingClass
{
    Percentage = y.Random.Int(70, 90),
});

Does anyone have an idea or suggestion how to set dynamic properties in this case?

Juliën
  • 9,047
  • 7
  • 49
  • 80

1 Answers1

2

First off, thank you for using Bogus!

Using the following code:

void Main()
{
   var foo = FakeFoos(1).First();
   foo.Dump();
   Console.WriteLine($"Percentage: {foo.Attributes.Percentage}");
}

Option 1 - Anonymous Type

The most elegant way to use dynamic would be to use an anonymous type:

public static IReadOnlyCollection<Foo> FakeFoos(int amount)
{
   var config = new Faker<Foo>()
       .StrictMode(false)
       .RuleFor(x => x.Id, y => y.Random.Guid().ToString("N"))
       .RuleFor(x => x.Attributes, y => new { Percentage = y.Random.Int(70, 90) });
   return config.Generate(amount);
}

enter image description here


Option 2 - ExpandoObject

More conventionally, using an ExpandoObject:

public static IReadOnlyCollection<Foo> FakeFoos(int amount)
{
   var config = new Faker<Foo>()
       .StrictMode(false)
       .RuleFor(x => x.Id, y => y.Random.Guid().ToString("N"))
       .RuleFor(x => x.Attributes, y =>
            {
               dynamic eo = new ExpandoObject();
               eo.Percentage = y.Random.Int(70, 90);
               return eo;
            });
   return config.Generate(amount);
}

enter image description here


Hope that helps, let me know if you have any more questions. :)

Community
  • 1
  • 1
Brian Chavez
  • 8,048
  • 5
  • 54
  • 47