8

Generic Action Delegate を作成しようとしています

  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?)    

私の GetSetterAction は ActionPerdicate を返します。ここでは、T は busPerson であり、Contravariance を念頭に置いて ActionPredicate に格納しようとしています。しかし、それは失敗します。さらに進む方法がわかりません。助けてください..!

4

1 に答える 1

8

一般的な反変性では、以下に示す理由により (ここを使用して) 、デリゲートをデリゲートに割り当てることができません。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ます。ただし、別の方法、つまり、パラメーターの型がソースよりも派生している型へのデリゲート参照をコピーすることは問題ありません。 MSDN には、一般的な共分散/逆分散のより完全な例があります。objectstring

したがって、 to の宣言を変更するactか、または常に return を返すようにメソッドをActionPredicate<busPerson, string> act記述することを検討する必要があります。それを行う場合は、型制約も追加する必要がありますGetSetterActionActionPredicate<busBase, string>

where T1 : busBase

メソッドに加えて、式の作成方法も変更する必要があるため、最初の 2 行を次のように置き換えます。

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>デリゲートの何が問題だったのでしょうか? あなたとまったく同じことをしているように見えますか?:)

于 2012-04-11T08:00:55.443 に答える