Temsilcilerdeki Fark (C#)

.NET Framework 3.5, C# içindeki tüm temsilcilerde temsilci türleriyle eşleşen yöntem imzaları için varyans desteği sunar. Bu, temsilcilere yalnızca eşleşen imzaları olan yöntemleri değil, aynı zamanda daha fazla türetilmiş tür (kovaryans) döndüren veya temsilci türü tarafından belirtilenden daha az türetilmiş türe (ters değişken) sahip parametreleri kabul eden yöntemleri de atayabileceğiniz anlamına gelir. Buna hem genel hem de genel olmayan temsilciler dahildir.

Örneğin, iki sınıfı ve iki temsilcisi olan aşağıdaki kodu göz önünde bulundurun: genel ve genel olmayan.

public class First { }  
public class Second : First { }  
public delegate First SampleDelegate(Second a);  
public delegate R SampleGenericDelegate<A, R>(A a);  

veya SampleGenericDelegate<A, R> türlerinin SampleDelegate temsilcilerini oluşturduğunuzda, aşağıdaki yöntemlerden herhangi birini bu temsilcilere atayabilirsiniz.

// Matching signature.  
public static First ASecondRFirst(Second second)  
{ return new First(); }  
  
// The return type is more derived.  
public static Second ASecondRSecond(Second second)  
{ return new Second(); }  
  
// The argument type is less derived.  
public static First AFirstRFirst(First first)  
{ return new First(); }  
  
// The return type is more derived
// and the argument type is less derived.  
public static Second AFirstRSecond(First first)  
{ return new Second(); }  

Aşağıdaki kod örneği, yöntem imzası ile temsilci türü arasındaki örtük dönüştürmeyi gösterir.

// Assigning a method with a matching signature
// to a non-generic delegate. No conversion is necessary.  
SampleDelegate dNonGeneric = ASecondRFirst;  
// Assigning a method with a more derived return type
// and less derived argument type to a non-generic delegate.  
// The implicit conversion is used.  
SampleDelegate dNonGenericConversion = AFirstRSecond;  
  
// Assigning a method with a matching signature to a generic delegate.  
// No conversion is necessary.  
SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst;  
// Assigning a method with a more derived return type
// and less derived argument type to a generic delegate.  
// The implicit conversion is used.  
SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;  

Daha fazla örnek için bkz . Temsilcilerde Varyansı Kullanma (C#) ve Func ve Eylem Genel Temsilcileri için Varyansı Kullanma (C#).

Genel Tür Parametrelerinde Varyans

.NET Framework 4 veya sonraki sürümlerinde, genel tür parametreleri tarafından belirtilen farklı türlere sahip genel temsilcilerin, türlerin varyansın gerektirdiği şekilde birbirlerinden devralınması durumunda birbirlerine atanabilmesi için, temsilciler arasında örtük dönüştürmeyi etkinleştirebilirsiniz.

Örtük dönüştürmeyi etkinleştirmek için, veya out anahtar sözcüğünü kullanarak in bir temsilcideki genel parametreleri birlikte değişken veya değişken karşıtı olarak açıkça bildirmeniz gerekir.

Aşağıdaki kod örneği, birlikte değişken genel tür parametresine sahip bir temsilciyi nasıl oluşturabileceğinizi gösterir.

// Type T is declared covariant by using the out keyword.  
public delegate T SampleGenericDelegate <out T>();  
  
public static void Test()  
{  
    SampleGenericDelegate <String> dString = () => " ";  
  
    // You can assign delegates to each other,  
    // because the type T is declared covariant.  
    SampleGenericDelegate <Object> dObject = dString;
}  

Yöntem imzalarını temsilci türleriyle eşleştirmek için yalnızca varyans desteği kullanıyorsanız ve ve out anahtar sözcüklerini kullanmıyorsanızin, bazen özdeş lambda ifadeleri veya yöntemleriyle temsilci örneği oluşturabileceğinizi, ancak bir temsilciyi diğerine atayamayacağınızı fark edebilirsiniz.

Aşağıdaki kod örneğinde, SampleGenericDelegate<String> devralınan Objectolmasına rağmen String açıkça 'a SampleGenericDelegate<Object>dönüştürülemez. Genel parametreyi T anahtar sözcüğüyle out işaretleyerek bu sorunu çözebilirsiniz.

public delegate T SampleGenericDelegate<T>();  
  
public static void Test()  
{  
    SampleGenericDelegate<String> dString = () => " ";  
  
    // You can assign the dObject delegate  
    // to the same lambda expression as dString delegate  
    // because of the variance support for
    // matching method signatures with delegate types.  
    SampleGenericDelegate<Object> dObject = () => " ";  
  
    // The following statement generates a compiler error  
    // because the generic type T is not marked as covariant.  
    // SampleGenericDelegate <Object> dObject = dString;  
  
}  

.NET'te Değişken Türü Parametreleri Olan Genel Temsilciler

.NET Framework 4, var olan çeşitli genel temsilcilerde genel tür parametreleri için varyans desteği sunar:

Daha fazla bilgi ve örnek için bkz . Func ve Eylem Genel Temsilcileri için Varyansı Kullanma (C#).

Genel Temsilcilerde Değişken Türü Parametrelerini Bildirme

Genel temsilcinin ortak değişken veya değişken karşıtı genel tür parametreleri varsa, değişken genel temsilci olarak anılabilir.

Anahtar sözcüğünü kullanarak genel bir temsilcide ortak değişken bir genel tür parametresi bildirebilirsiniz out . Kovarant türü, yöntem bağımsız değişkenlerinin türü olarak değil, yalnızca yöntem dönüş türü olarak kullanılabilir. Aşağıdaki kod örneği, birlikte değişken bir genel temsilcinin nasıl bildir yapılacağını gösterir.

public delegate R DCovariant<out R>();  

Anahtar sözcüğünü kullanarak genel bir temsilcide genel tür parametresi contravariant bildirebilirsiniz in . Değişken karşıtı tür, yöntem dönüş türü olarak değil, yalnızca yöntem bağımsız değişkenlerinin türü olarak kullanılabilir. Aşağıdaki kod örneği, değişken karşıtı genel temsilcinin nasıl bildir yapılacağını gösterir.

public delegate void DContravariant<in A>(A a);  

Önemli

ref, inve out C# içindeki parametreler değişken olarak işaretlenemez.

Aynı temsilcide hem varyansı hem de kovaryansı desteklemek, ancak farklı tür parametreleri için de mümkündür. Bu, aşağıdaki örnekte gösterilir.

public delegate R DVariant<in A, out R>(A a);  

Değişken Genel Temsilcilerini Örnekleme ve Çağırma

Değişken temsilcilerin örneğini oluşturup çağırdığınız gibi değişken temsilcileri de başlatabilir ve çağırabilirsiniz. Aşağıdaki örnekte temsilcinin örneği bir lambda ifadesiyle oluşturulur.

DVariant<String, String> dvariant = (String str) => str + " ";  
dvariant("test");  

Değişken Genel Temsilcilerini Birleştirme

Değişken temsilcilerini birleştirmeyin. Combine yöntemi değişken temsilci dönüştürmeyi desteklemez ve temsilcilerin tam olarak aynı türde olmasını bekler. Bu, aşağıdaki kod örneğinde gösterildiği gibi, yöntemini veya işlecini kullanarak Combine+ temsilcileri birleştirdiğinizde bir çalışma zamanı özel duruma yol açabilir.

Action<object> actObj = x => Console.WriteLine("object: {0}", x);  
Action<string> actStr = x => Console.WriteLine("string: {0}", x);  
// All of the following statements throw exceptions at run time.  
// Action<string> actCombine = actStr + actObj;  
// actStr += actObj;  
// Delegate.Combine(actStr, actObj);  

Değer ve Başvuru Türleri için Genel Tür Parametrelerinde Varyans

Genel tür parametreleri için varyans yalnızca başvuru türleri için desteklenir. Örneğin, DVariant<int> tamsayı bir değer türü olduğundan örtük olarak veya DVariant<long>olarak dönüştürülemezDVariant<Object>.

Aşağıdaki örnek, genel tür parametrelerindeki varyansın değer türleri için desteklenmediğini gösterir.

// The type T is covariant.  
public delegate T DVariant<out T>();  
  
// The type T is invariant.  
public delegate T DInvariant<T>();  
  
public static void Test()  
{  
    int i = 0;  
    DInvariant<int> dInt = () => i;  
    DVariant<int> dVariantInt = () => i;  
  
    // All of the following statements generate a compiler error  
    // because type variance in generic parameters is not supported  
    // for value types, even if generic type parameters are declared variant.  
    // DInvariant<Object> dObject = dInt;  
    // DInvariant<long> dLong = dInt;  
    // DVariant<Object> dVariantObject = dVariantInt;  
    // DVariant<long> dVariantLong = dVariantInt;
}  

Ayrıca bkz.