2013-09-03 24 views
6

Bir özellik üyesini çekmek ve üzerinde hareket etmek için İfade parametresini kullanan bazı uzantı yöntemleri var ve üzerinde bir üye için IEnumerable olduğu özel durum için bir aşırı yük var <>. Ancak, genel bir sınıfın içinden çağrıldığında beklenen yöntem yükü ile eşleşmiyor gibi görünmüyor ('un altındaki r4 için ). Sınıfın dışında doğru yöntem seçilir.Genel türleri ve İfadeleri kullanarak uzantı yöntemi seçimi

Burada neler oluyor? Bu işe yarayacak mı yoksa yeni bir yaklaşım bulmam gerekecek mi?

public class Test 
{ 
    public void MyTest() 
    { 
     // returns "Object" 
     var r1 = new MyClass<object>().Ext(a => a.Content); 

     // returns "Enumerable" 
     var r2 = new MyClass<IEnumerable<object>>().Ext(a => a.Content); 

     // returns "Object" 
     var r3 = new MyClass<object>().TestExt(); 

     // returns "Object" (I was expecting "Enumerable") 
     var r4 = new MyClass<IEnumerable<object>>().TestExt(); 

     // returns "Enumerable" 
     var r5 = new MyClass<int>().TestExt2(); 
    } 
} 

public class MyClass<T> 
{ 
    public T Content { get; set; } 

    public IEnumerable<object> OtherContent { get; set; } 

    public string TestExt() 
    { 
     return this.Ext(a => a.Content); 
    } 

    public string TestExt2() 
    { 
     return this.Ext(a => a.OtherContent); 
    } 
} 

public static class MyExtensions 
{ 
    public static string Ext<T>(this T obj, Expression<Func<T, IEnumerable<object>>> memberExpression) 
    { 
     return "Enumerable"; 
    } 

    public static string Ext<T>(this T obj, Expression<Func<T, object>> memberExpression) 
    { 
     return "Object"; 
    } 
} 
+0

Burada sorun ne? –

+0

@KingKing "r4" bildiriminin yanındaki yorumu görün –

cevap

4

Jenerik dinamik yazarak değildir (Bu C# 5 olan). Aramak için hangi aşırı yükleme derleme zamanında dondurulur. Program daha sonra çalıştırıldığında, değişken daha spesifik bir çalışma zamanı tipine sahip olsa bile, bu aşırı bir yükün derlenme zamanında sabitlenmesinden dolayı önemli değildir.

Sizin yöntemi:

public string TestExt() 
{ 
    return this.Ext(a => a.Content); 
} 

Ext biri belirli aşırı yüklenmesine derleme sırasında bağlamak zorundadır. MyClass<T> sınıfındaki T (a.Content tipi) ile ilgili bildiğimiz her şey, object'a dönüştürülebilir olduğundan, seçim yapmak için gerçekten sadece bir aşırı yükleme var, bu yüzden derleyici için bu çok kolay.

Bundan sonra, TestExt yöntem gövdesi, Ext özel aşırı yüklenmesini çağırmak için kodlanmıştır.


DÜZENLEME: İşte daha basit örnek:

static void Main() 
{ 
    IEnumerable<object> e = new List<object>(); 
    var r = Generic(e); 
} 

static string Generic<T>(T x) 
{ 
    return Overloaded(x); 
} 

static string Overloaded(IEnumerable<object> x) 
{ 
    return "Enumerable"; 
} 
static string Overloaded(object x) 
{ 
    return "Object"; 
} 

ve şimdiye kadar anladığımız kadarıyla, r"Object" olur.

(T'u bir şekilde kısıtladıysanız, örneğin where T : IEnumerable<object>, işler farklı olabilir).

Ayrıca bu, operatörler için de geçerlidir. Örneğin, == operatörü, genel referans türleri için ve bir başka dizge için çalışacak şekilde aşırı yüklenmiştir.

static void Main() 
{ 
    string str1 = "abc"; 
    string str2 = "a"; 
    str2 += "bc";  // makes sure this is a new instance of "abc" 

    bool b1 = str1 == str2;  // true 
    bool b2 = Generic(str1, str2); // false 
} 

static bool Generic<T>(T x, T y) where T : class 
{ 
    return x == y; 
} 

b2false olur burada: Yani aşağıdaki örnekte, operatör == önce gelen Overloaded rol alır.

İlgili konular