Search code examples
c#genericssystem.reflectiondynamic-expression

Dynamic expression incorrect number of parameters


I am using reflection and dynamic expressions to auto-populate a class and all its properties with fake data using bogus, my code looks like:

   static Faker<T> AutoInferRules<T>() where T : class, new(){
    var faker = new Faker<T>();

    foreach (var property in typeof(T).GetProperties())
    {
        if (property.Name == "Schema")
        {
            continue;
        }

        try
        {
            if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
            {
                // Recursively infer rules for nested classes
                var nestedFaker = typeof(Program)
                    .GetMethod("AutoInferRules", BindingFlags.NonPublic | BindingFlags.Static)
                    ?.MakeGenericMethod(property.PropertyType)
                    .Invoke(null, null);

                faker = faker.RuleFor(property.Name, _ => nestedFaker);
            }
            else if (property.PropertyType == typeof(Double))
            {
                faker = faker.RuleFor(property.Name, (f, _) => f.Random.Double());
            }
            else if (property.PropertyType == typeof(Nullable<Boolean>))
            {
                faker = faker.RuleFor(property.Name, (f, _) => f.Random.Bool());
            }
            
            else if (property.PropertyType.IsGenericType &&
                     typeof(IList<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
            {
                // Handle the case where the property is a List of objects
                var elementType = property.PropertyType.GetGenericArguments()[0];
                
                //gets defintion for GenerateList<T>
                var generateListMethod = typeof(Program)
                    .GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Last()
                    ?.MakeGenericMethod(elementType);
                
                var listExpression = Expression.Lambda<Func<T, List<T>>>(
                    Expression.Call(
                        generateListMethod,
                        Expression.New(generateListMethod!.ReturnType)
                    ),
                    Expression.Parameter(typeof(T), "x")
                );

                faker = faker.RuleFor(property.Name,_ => listExpression);

            }
           
            else
            {
                // Generate rules for non-nested properties
                faker = faker.RuleFor(property.Name, (f, _) => f.Random.AlphaNumeric(10));
            }
        }
        catch (Exception ex)
        {
            Log.Logger.Error(ex, "error processing field {PropertyName}", property.Name);
        }
 
    }

    return faker;

} static List GenerateList() where T : class, new() { // Here you can customize the logic to generate and populate the list var faker = AutoInferRules(); return new List { faker.Generate() }; }

When I run this code I get the following error:

Incorrect number of arguments supplied for call to method 'System.Collections.Generic.List`1[RandomFlightDataGen.Model.IATA_AIDX_FlightLegNotifRQ.FlightLegType] <$>g__GenerateList|0_2FlightLegType' (Parameter 'method')

The property it is failing on is a List<FlightLegType>

My Expression.Lambda looks like it matches the signature of the method I am trying to dynamically call

static List<T> GenerateList<T>() where T : class, new()

Anyone any ideas?


Solution

  • Not sure why you are passing an instance to a static function, or what the Expression.New was supposed to do.

    Looks like you just need:

    var listExpression = Expression.Lambda<Func<T, List<T>>>(
      Expression.Call(null, generateListMethod),
      Expression.Parameter(typeof(T), "x")
    );