逆变表达式中(Contravariance in Expressions)

2019-07-28 21:30发布

我试图创建一个通用的动作代表

  delegate void ActionPredicate<in T1, in T2>(T1 t1, T2 t2);

public static ActionPredicate<T,string> GetSetterAction<T>(string fieldName) 
    {

        ParameterExpression targetExpr = Expression.Parameter(typeof(T), "Target");
        MemberExpression fieldExpr = Expression.Property(targetExpr, fieldName);
        ParameterExpression valueExpr = Expression.Parameter(typeof(string), "value");

        MethodCallExpression convertExpr = Expression.Call(typeof(Convert), "ChangeType", null, valueExpr, Expression.Constant(fieldExpr.Type));

        UnaryExpression valueCast = Expression.Convert(convertExpr, fieldExpr.Type);
        BinaryExpression assignExpr = Expression.Assign(fieldExpr, valueCast);
        var result = Expression.Lambda<ActionPredicate<T, string>>(assignExpr, targetExpr, valueExpr);
        return result.Compile();
    }

这里是我的来电显示

 ActionPredicate<busBase, string> act = DelegateGenerator.GetSetterAction<busPerson>("FirstName");

这里是业务对象

 public abstract class busBase 
{

}
public class busPerson : busBase
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public string GetFullName()
    {
        return string.Format("{0} {1}", FirstName, LastName);
    }
}

这里是错误我在编译过程中得到

Cannot implicitly convert type 'BusinessObjects.ActionPredicate<BusinessObjects.busPerson,string>' to 'BusinessObjects.ActionPredicate<BusinessObjects.busBase,string>'. An explicit conversion exists (are you missing a cast?)    

这里T是busPerson我GetSetterAction将返回ActionPerdicate,我试图将其存储在ActionPredicate牢记约逆变。 但它失败。 我不知道如何进一步进行。 请帮忙..!

Answer 1:

通用逆变不允许为委托分配D<TDerived>的委托D<TBase>因为下面展示的原因(使用Action<T1>这里):

Action<string> m1 = MyMethod; //some method to call
Action<object> m2 = m1; //compiler error - but pretend it's not.
object obj = new object();

m2(obj);  //runtime error - not type safe

正如你所看到的,如果我们被允许做这个任务,我们将被打破类型安全,因为我们希望能够尝试并调用委托m1通过传递和实例object ,而不是string 。 要的其他方式,但是,即复制委托参考类型,其参数类型比源多个派生是好的。 MSDN有通用的CO /反向变化的更完整的例子 。

因此,你要么需要申报改变actActionPredicate<busPerson, string> act ,或者更可能的是,考虑写GetSetterAction方法总是返回ActionPredicate<busBase, string> 。 如果你这样做,你也应该添加类型约束

where T1 : busBase

的方法,你还需要改变你的表情是如何构建,更换前两行,如下所示:

ParameterExpression targetExpr = Expression.Parameter(typeof(busBase), "Target");
//generate a strongly-typed downcast to the derived type from busBase and
//use that as the type on which the property is to be written
MemberExpression fieldExpr = Expression.Property(
  Expression.Convert(targetExpr, typeof(T1)), fieldName);

添加通用约束是一个很好的接触,以确保这种沮丧的将永远是任何有效的T1

在一个稍微不同的说明-什么是错与Action<T1, T2>委托? 这似乎做同样的事情作为你的吗? :)



文章来源: Contravariance in Expressions