Aracılığıyla paylaş


Değişken Genel Arabirimleri Oluşturma (C#)

Arabirimlerdeki genel tür parametrelerini birlikte değişken veya değişken karşıtı olarak bildirebilirsiniz. Kovaryans, arabirim yöntemlerinin genel tür parametreleri tarafından tanımlanandan daha fazla türetilmiş dönüş türüne sahip olmasını sağlar. Contravariance, arabirim yöntemlerinin genel parametreler tarafından belirtilenden daha az türetilmiş bağımsız değişken türlerine sahip olmasını sağlar. Kovaryant veya kontravaryant genel tür parametrelerine sahip bir genel arayüze varyant adı verilir.

Uyarı

.NET Framework 4, çeşitli mevcut genel arabirimler için varyans desteği sunar. .NET'teki değişken arabirimlerin listesi için bkz. Genel Arabirimlerde Varyans (C#).

Değişken Genel Arabirimleri Bildirme

in ve out anahtar sözcüklerini genel tür parametreleri için kullanarak varyant genel arabirimler bildirebilirsiniz.

Önemli

refC# içindeki , inve out parametreleri değişken olamaz. Değer türleri de varyansı desteklemez.

Anahtar kelime out ile bir genel tür parametresini kovaryant olarak bildirebilirsiniz. Kovarant türü aşağıdaki koşulları karşılamalıdır:

  • Tür yalnızca yöntemlerin arabirimdeki dönüş türü olarak kullanılır ve yöntem parametrelerinin türü olarak kullanılmaz. Bu, türün R birlikte değişken olarak bildirildiği aşağıdaki örnekte gösterilmiştir.

    interface ICovariant<out R>
    {
        R GetSomething();
        // The following statement generates a compiler error.
        // void SetSomething(R sampleArg);
    
    }
    

    Bu kuralın bir özel durumu vardır. Yöntem parametresi olarak kontravarvan bir genel temsilciniz varsa, türü temsilci için genel tür parametresi olarak kullanabilirsiniz. Bu, aşağıdaki örnekteki tür R tarafından gösterilmiştir. Daha fazla bilgi için bkz. Temsilcilerde Varyans (C#) ve Func ve Eylem Genel Temsilcileri için Varyansı Kullanma (C#).

    interface ICovariant<out R>
    {
        void DoSomething(Action<R> callback);
    }
    
  • Tür, arabirim yöntemleri için genel bir kısıtlama olarak kullanılmaz. Bu, aşağıdaki kodda gösterilmiştir.

    interface ICovariant<out R>
    {
        // The following statement generates a compiler error
        // because you can use only contravariant or invariant types
        // in generic constraints.
        // void DoSomething<T>() where T : R;
    }
    

Anahtar sözcüğü in kullanarak bir genel tür parametresini contravaryant olarak bildirebilirsiniz. Arabirim yöntemlerinin dönüş türü olarak değil, yalnızca yöntem bağımsız değişkenlerinin türü olarak kullanılabilen bir kontravaryant türdür. Kontravaryant tür, genel kısıtlamalar için de kullanılabilir. Aşağıdaki kod, kontravaryant bir arayüzün nasıl tanımlanacağını ve yöntemlerinden biri için genel bir kısıtın nasıl kullanılacağını gösterir.

interface IContravariant<in A>
{
    void SetSomething(A sampleArg);
    void DoSomething<T>() where T : A;
    // The following statement generates a compiler error.
    // A GetSomething();
}

Aynı arabirimde, ancak aşağıdaki kod örneğinde gösterildiği gibi farklı tür parametreleri için hem kovaryansı hem de kontrvaryansı desteklemek de mümkündür.

interface IVariant<out R, in A>
{
    R GetSomething();
    void SetSomething(A sampleArg);
    R GetSetSomethings(A sampleArg);
}

Değişken Genel Arabirimleri Gerçekleştirme

Sabit arabirimler için kullanılan söz dizimini kullanarak sınıflarda değişken genel arabirimler uygularsınız. Aşağıdaki kod örneğinde, genel bir sınıfta birlikte değişken arabiriminin nasıl uygulandığı gösterilmektedir.

interface ICovariant<out R>
{
    R GetSomething();
}
class SampleImplementation<R> : ICovariant<R>
{
    public R GetSomething()
    {
        // Some code.
        return default(R);
    }
}

Değişken arabirimleri uygulayan sınıflar sabittir. Örneğin, aşağıdaki kodu göz önünde bulundurun.

// The interface is covariant.
ICovariant<Button> ibutton = new SampleImplementation<Button>();
ICovariant<Object> iobj = ibutton;

// The class is invariant.
SampleImplementation<Button> button = new SampleImplementation<Button>();
// The following statement generates a compiler error
// because classes are invariant.
// SampleImplementation<Object> obj = button;

Değişken Veri Tipi Arabirimlerini Genişletme

Bir değişken genel arabirimini genişlettiğiniz zaman, türetilmiş arabirimin in varyansı destekleyip desteklemediğini açıkça belirtmek için ve out anahtar sözcüklerini kullanmanız gerekir. Derleyici, genişletilmekte olan arabirimden varyansı çıkarmıyor. Örneğin, aşağıdaki arabirimleri göz önünde bulundurun.

interface ICovariant<out T> { }
interface IInvariant<T> : ICovariant<T> { }
interface IExtCovariant<out T> : ICovariant<T> { }

Arabirimde IInvariant<T>, genel tür parametresi T değişmezken, IExtCovariant<out T> tür parametresi kovaryanttadır; ancak her iki arabirim de aynı arabirimi genişletir. Aynı kural, değişken karşıtı genel tür parametrelerine de uygulanır.

Genel tür parametresinin T birlikte değişken olduğu bir arabirimi ve aynı zamanda tersine değişken olduğu bir arabirimi, genişletme arabiriminde genel tür parametresi T sabit olduğunda genişleten bir arabirim oluşturabilirsiniz. Bu, aşağıdaki kod örneğinde gösterilmiştir.

interface ICovariant<out T> { }
interface IContravariant<in T> { }
interface IInvariant<T> : ICovariant<T>, IContravariant<T> { }

Ancak, bir genel tür parametresi T tek bir arabirimde birlikte değişken olarak bildirilirse, genişletme arabiriminde değişken karşıtı olarak bildiremezsiniz veya tersi de geçerlidir. Bu, aşağıdaki kod örneğinde gösterilmiştir.

interface ICovariant<out T> { }
// The following statement generates a compiler error.
// interface ICoContraVariant<in T> : ICovariant<T> { }

Belirsizlikten Kaçınma

Değişken genel arabirimleri uyguladığınızda, varyans bazen belirsizliğe yol açabilir. Böyle bir belirsizlikten kaçınılmalıdır.

Örneğin, bir sınıfta farklı genel tür parametreleriyle aynı değişken genel arabirimini açıkça uygularsanız, belirsizlik oluşturabilir. Derleyici bu durumda bir hata üretmez, ancak çalışma zamanında hangi arabirim uygulamasının seçileceği belirtilmez. Bu belirsizlik, kodunuzda küçük hatalar oluşmasına neden olabilir. Aşağıdaki kod örneğini göz önünde bulundurun.

// Simple class hierarchy.
class Animal { }
class Cat : Animal { }
class Dog : Animal { }

// This class introduces ambiguity
// because IEnumerable<out T> is covariant.
class Pets : IEnumerable<Cat>, IEnumerable<Dog>
{
    IEnumerator<Cat> IEnumerable<Cat>.GetEnumerator()
    {
        Console.WriteLine("Cat");
        // Some code.
        return null;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        // Some code.
        return null;
    }

    IEnumerator<Dog> IEnumerable<Dog>.GetEnumerator()
    {
        Console.WriteLine("Dog");
        // Some code.
        return null;
    }
}
class Program
{
    public static void Test()
    {
        IEnumerable<Animal> pets = new Pets();
        pets.GetEnumerator();
    }
}

Bu örnekte, pets.GetEnumerator yöntemin Cat ile Dog arasında nasıl seçim yaptığı belirtilmemiştir. Bu, kodunuzda sorunlara neden olabilir.

Ayrıca bakınız