kan*_*ans 8 c# expression covariance contravariance expression-trees
我正在尝试创建一个通用操作代理
delegate void ActionPredicate<in T1, in T2>(T1 t1, T2 t2);
Run Code Online (Sandbox Code Playgroud)
和
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();
}
Run Code Online (Sandbox Code Playgroud)
这是我的来电者
ActionPredicate<busBase, string> act = DelegateGenerator.GetSetterAction<busPerson>("FirstName");
Run Code Online (Sandbox Code Playgroud)
这是业务对象
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我在编译期间得到的错误
Cannot implicitly convert type 'BusinessObjects.ActionPredicate<BusinessObjects.busPerson,string>' to 'BusinessObjects.ActionPredicate<BusinessObjects.busBase,string>'. An explicit conversion exists (are you missing a cast?)
Run Code Online (Sandbox Code Playgroud)
我的GetSetterAction返回ActionPerdicate,其中T是busPerson,我试图将它存储在ActionPredicate中,记住Contravariance.但它失败了.我不知道如何继续前进.请帮忙..!
通用逆变并不会让你一个委托分配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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,如果我们被允许执行此分配,那么我们将破坏类型安全性,因为我们能够尝试m1通过传递和实例来调用委托,object而不是string.但是,另一方面,即将委托引用复制到参数类型比源更多的类型是可以的. MSDN有一个更完整的通用协同方差的例子.
因此你要么需要改变的声明act来ActionPredicate<busPerson, string> act,或者更可能的是,考虑写的GetSetterAction总是返回方法ActionPredicate<busBase, string>.如果这样做,您还应该添加类型约束
where T1 : busBase
Run Code Online (Sandbox Code Playgroud)
对于该方法,您还需要更改表达式的构建方式,替换前两行,如下所示:
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);
Run Code Online (Sandbox Code Playgroud)
添加通用约束是一种很好的方法,可以确保此向下转换始终对任何转发都有效T1.
稍微不同的说明 - Action<T1, T2>代表有什么问题?它似乎与你的完全一样?:)
| 归档时间: |
|
| 查看次数: |
556 次 |
| 最近记录: |