Anlayış Kovaryant ve Karşıtı arayüzleri C#
C okuyorum bir kitabı bu karşılaştığım# ama zorluk onlara anlayış, muhtemelen bağlam eksikliği nedeniyle yaşıyorum.
Ne olduklarını ve ne için yararlıdır ne güzel kısa ve öz bir açıklaması var mı?
Açıklama için Edit:
Arayüz kovaryant:
interface IBibble<out T>
.
.
Arayüz karşıtı:
interface IBibble<in T>
.
.
CEVAP
<out T>
ile bir hiyerarşi içinde yukarı doğru olarak arabirimi başvuru davranabilirsiniz.
<in T>
ile bir hiearchy aşağıya doğru olarak arabirimi başvuru davranabilirsiniz.
Beni daha fazla İngilizce açısından açıklayayım.
Haydi hayvanat bahçesi hayvanları listesi alınıyor ki, ve bunları işlemek niyetinde. Tüm hayvanlar (Hayvanat Bahçesi) adı ve benzersiz bir KİMLİĞİ vardır. Bazı hayvanlar, memeliler, bazı sürüngenler, bazı amfibiler, balık, vb. ama hepsi hayvan.
Yani, elindeki listeyi hayvanlar (içeren farklı hayvan türleri), ne olursa olsun tüm hayvanları olan bir isim, yani belli ki emniyette olur adını almak için bütün hayvanlar.
Ancak, kuşlar sadece bir liste var, ama hayvanlar gibi onları tedavi etmek gerekiyorsa, bu ne iş? Sezgisel olarak, çalışması gerekir, ama C# 3.0 ve daha önce, bu kod parçası derlenir değil:
IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
Bunun nedeni, derleyici "niyetin ne, ya." bilmez ki ^em>olabilironu aldıktan sonra hayvan koleksiyonu. Hepsi bilir, olabilir bir yolu IEnumerable<T>
koymak bir nesne arkasına listesi, ve bu potansiyel olarak izin koymak bir hayvan değil bir balık, bir koleksiyon olması gerekiyor içeren tek balık.
Diğer bir deyişle, derleyici bu izin verilmez garanti:
animals.Add(new Mammal("Zebra"));
Yani derleyici sadece düpedüz kodunuzu derlemek için reddediyor. Bu kovaryans.
Bu contravariance bakalım.
Bizim Hayvanat Bahçesi tüm hayvanlar işleyebilir beri, kesinlikle balık işlemek, bizim Hayvanat Bahçesine bazı balık eklemek için gayret edelim.
C# 3.0 ve daha önce bu derleme değil:
List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
fishes.Add(new Fish("Guppy"));
Burada, derleyiciolabilirbu yöntem sadece balık ... farklı türleri değişirse yani hayvanlardır, çünkü List<Animal>
iade olsa bile bu kod parçası, bu izin verin
List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));
İşe yarar o zaman, ama derleyici bu yapmaya çalıştığın olmadığını belirlemek:
List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
Fish firstFist = fishes[0];
Bu liste aslında hayvanların bir liste olduğu için buna izin verilmiyor.
Contra - ve-varyans co nesne başvurularını nasıl davrandığını ve onları yapmakta bir şey yok.
C# 4.0 özellikle in
out
anahtar veya başka bir arabirim işaretleri. in
ile genel bir tür (genellikle) T yerde hakkın vargiriş-pozisyon yöntem bağımsız değişkenleri anlamına gelir, ve yazma özellikleri.
out
ile genel türü yerleştirmek için izin veriliyorçıktı-pozisyonlar dönüş değerleri yöntemi, salt-okunur özellikler ve Yöntem parametreleri.
Bu kod ile yapmaya niyetlendiği yapmak için izin verir:
IEnumerable<Animal> animals = GetFishes(); // returns IEnumerable<Fish>
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe
List<T>
- ve-yönleri, her iki T, co-varyant ne de contra-değişken de, ama nesneleri, bu gibi eklemek için izin veren bir arayüz.
interface IWriteOnlyList<in T>
{
void Add(T value);
}
bunu yapmana izin verir:
IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals(); // still returns
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe
Burada kavramları gösteren birkaç video:
- Covariance and Contravariance - VS2010 C# Part 1 of 3
- Covariance and Contravariance - VS2010 C# Part 2 of 3
- Covariance and Contravariance - VS2010 C# Part 3 of 3
İşte size bir örnek:
namespace SO2719954
{
class Base { }
class Descendant : Base { }
interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }
class Program
{
static void Main(string[] args)
{
// We can do this since every Descendant is also a Base
// and there is no chance we can put Base objects into
// the returned object, since T is "out"
// We can not, however, put Base objects into b, since all
// Base objects might not be Descendant.
IBibbleOut<Base> b = GetOutDescendant();
// We can do this since every Descendant is also a Base
// and we can now put Descendant objects into Base
// We can not, however, retrieve Descendant objects out
// of d, since all Base objects might not be Descendant
IBibbleIn<Descendant> d = GetInBase();
}
static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}
static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}
Bu işaretleri olmadan, aşağıdaki derleme:
public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant
ya da bu:
public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants
Anlayış NSWindowController açıklama...
Anlayış "Turk"...
Anlayış Blok ve Blok Tip Profesyonel...
Sorun anlayış C# dili şartnamede açıkl...
Özyinelemeli olarak tanımlanan bir anl...