简体   繁体   中英

Casting Generic Parameters as Dynamic

I'm writing a rule based mock data generator. But to save time I've decided to use a dynamic container to store rules.

    public void AddGlobalRule<T, TProperty>(Expression<Func<T, TProperty>> property, Func<Faker, dynamic, dynamic, dynamic> rule)
        where T : class
    {
        var propertyName = ((MemberExpression)property.Body).Member.Name;
        this.AddRawRule(typeof(T), rule, propertyName);
    }

    public void AddRawRule(Type entityType, Func<Faker, dynamic, dynamic, dynamic> rule, string propertyName)
    {
        if (false == this._ruleMap.ContainsKey(entityType))
        {
            this._ruleMap.Add(entityType, new RuleSet());
        }

        var ruleset = this._ruleMap.Get(entityType);
        ruleset.Add((propertyName, rule));
    }

The issue is that this code doesn't have intellisense, I would really like to write the function like so:

public void AddGlobalRule<T, TProperty>(Expression<Func<T, TProperty>> property, Func<Faker, T, T, TProperty> rule)
    where T : class
{
    var propertyName = ((MemberExpression)property.Body).Member.Name;
    var dynamicRule = rule as Func<Faker, dynamic, dynamic, dynamic>;
    this.AddRawRule(typeof(T), dynamicRule, propertyName);
}

Edit for clarity:

If I use Func<Faker, T, T, TProperty> rule as the input into the function, when I use it

 generator.AddGlobalRule<Employee, string>(x => x.Name, 
    (f, previous, current) => {
       //If I use Dynamic I don't have intellisense here
       return current.FirstName + current.LastName;
    })

However when I try to cast the dynamic rule is null,

var dynamicRule = rule as Func<Faker, dynamic, dynamic, dynamic>;

How can I cast to the my rule, so that I can preserve intellisense?

Right. Casting to Func<Faker, dynamic, dynamic, dynamic> is effectively the same as casting to Func<Faker, object, object, object> , just with dynamic resolution. So you can't do that because the inputs to Func are contravariant not covariant (a delegate that takes an arg of T will not also accept an argument of object ).

(I'd ask yourself why you store in the map with dynamic arguments and not just plain old object s? Are you actually consuming these dynamically?)

Anyhow, you need to wrap your delegate in something that downcasts to the required types like:

Func<Faker, dynamic, dynamic, dynamic> dynamicRule = (a, b, c) => rule(a, (T)b, (T)c);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM