2012-04-11 12 views
8

ben bir Genel Eylem temsilci oluşturmak çalışıyorumcontravariance Expressions

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

ve burada

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(); 
    } 

ve

Arayan

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

ve burada iş nesnesi

olduğunu
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); 
    } 
} 

ve burada I My GetSetterAction T busPerson olduğu gibi burada ActionPerdicate dönüyor ve ben ActionPredicate contravariance hakkında akılda tutarak saklayın çalışıyorum

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

derleme sırasında ne elde hatadır. Ama başarısız oluyor. Daha fazla nasıl ilerleyeceğimi bilmiyorum. Lütfen yardım et..! Gördüğünüz gibi

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 

, biz izin verilirse:

+0

Açık dönüşümü denediniz mi? – McGarnagle

cevap

8

Jenerik contravariance değil (burada Action<T1> kullanarak) D<TBase> çünkü aşağıda gösterilmiştir aklın bir temsilciye bir temsilci D<TDerived> atamak için izin yapar Bu ödevi yapalım, daha sonra tip güvenliği emniyeti verecektik çünkü m1 delegesini object ve string no'lu örneklerini geçirerek örnekleyebiliriz. Bununla birlikte, diğer yoldan gitmek, yani, parametre tipini kaynaktan daha türetilen bir türe bir temsilci başvurusu kopyalamak gayet iyi. MSDN has a more complete example of generic co/contra variance.

nedenle, daha büyük olasılıkla ActionPredicate<busPerson, string> act veya e act beyanı değiştirmek her zaman ActionPredicate<busBase, string> dönmek için GetSetterAction yöntemi yazma dikkate almak gerekir ya. Bunu yaparsanız, ayrıca yöntemin için tip kısıtlamasını

where T1 : busBase 

eklemek gerekir ve aşağıdaki gibi aynı zamanda ilk iki satırı değiştirin, ifadeniz inşa şeklini değiştirmek gerekir:

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

Genel kısıtlama eklemek, bu downcast'in her zaman T1 için geçerli olmasını sağlamak için hoş bir dokunuştur.

Biraz farklı bir notta - Action<T1, T2> temsilcisinin nesi yanlış? Seninkiyle aynı şeyi mi yapıyorsun? :)

+0

Önerdiğiniz gibi, Action döndürmek için GeetSetterAction'ı değiştirmeyi denedim ancak "BusinessObjects.busPerson" türünde 'ParameterExpression' parametresi 'BusinessObjects.busBase' türünde delegate parametresi için kullanılamaz. Bu hatayı bu satırda alıyorum. "var sonuç = Expression.Lambda > (assignExpr, targetExpr, valueExpr);" – kans

+0

@kans - ah evet - ifade ağacını biraz farklı bir şekilde oluşturmalısınız: "fieldExpr" oluştururken "busBase" konumundan "T1" 'e kadar. Cevabımı güncellediniz. –

+0

Müthiş. Çok teşekkürler. harika çalışıyor. İfadelere dayalı bir Kural Motoru oluşturuyorum. Bu konuda bazı düşüncelerinizi atlatabilir misiniz? – kans

İlgili konular