Herhangi bir uyarı veya contravariance belirsizlik neden hata (veya çalışma zamanı hatası)
İlk olarak, bir hatırlayın .NET String
IConvertible
ICloneable
Her ikisi de.
Şimdi, çok basit aşağıdaki kodu göz önünde bulundurun:
//contravariance "in"
interface ICanEat<in T> where T : class
{
void Eat(T food);
}
class HungryWolf : ICanEat<ICloneable>, ICanEat<IConvertible>
{
public void Eat(IConvertible convertibleFood)
{
Console.WriteLine("This wolf ate your CONVERTIBLE object!");
}
public void Eat(ICloneable cloneableFood)
{
Console.WriteLine("This wolf ate your CLONEABLE object!");
}
}
Daha sonra aşağıdaki (bazı yöntem içinde) deneyin:
ICanEat<string> wolf = new HungryWolf();
wolf.Eat("sheep");
Bu derler, bir tane alırhayırderleyici hata ya da uyarı. Çalışırken, yöntemi HungryWolf
class
benim bildiriminde arayüzü liste sırasına bağlıdır aramış gibi görünüyor. (Virgülle ayrılmış (,
) ayrılmış listesinde iki arayüz değiştirmeyi deneyin.)
Soru basit:Bu derleme bir uyarı (veya çalışma zamanında atmak) vermek gerekmez mi?
Muhtemelen bu gibi bir kod ile gelip ilk kişi ben değilim. Kullandımcontravariancearabirimi, ama pek benzer bir örnek yapabilirsinizcovarainacearabirimi. Ve aslında Mr Lippert did just that uzun zaman önce. Onun blog yorum, hemen hemen herkes bir hata olması gerektiğini kabul eder. Henüz bu sessizce sağlar.Neden?
---
Genişletilmiş soru:
String
hem Iconvertible
(arayüz) ve ICloneable
(arayüz) biz istismar yukarıda. Bu iki arabirimi de diğer türemiştir.
Şimdi burada, bir anlamda, biraz daha kötü olduğunu temel sınıflar ile bir örnek.
StackOverflowException
SystemException
(direct base class) ve Exception
(temel sınıf temel sınıf) olduğunu unutmayın. Daha sonra ICanEat<>
eskisi gibi (varsa):
class Wolf2 : ICanEat<Exception>, ICanEat<SystemException> // also try reversing the interface order here
{
public void Eat(SystemException systemExceptionFood)
{
Console.WriteLine("This wolf ate your SYSTEM EXCEPTION object!");
}
public void Eat(Exception exceptionFood)
{
Console.WriteLine("This wolf ate your EXCEPTION object!");
}
}
Bunu Test:
static void Main()
{
var w2 = new Wolf2();
w2.Eat(new StackOverflowException()); // OK, one overload is more "specific" than the other
ICanEat<StackOverflowException> w2Soe = w2; // Contravariance
w2Soe.Eat(new StackOverflowException()); // Depends on interface order in Wolf2
}
Hala herhangi bir uyarı, hata veya özel durum. Hala arayüzü class
beyan sipariş listesi değişir. Ama daha kötü oluyor bence sebebi bu zaman birisi aşırı çözümleme her zaman sadece Exception
daha da özel, çünkü SystemException
alacağını düşünüyor olabilir.
Bounty önce durumu açıldı: iki kullanıcılardan gelen Üç cevap.
Ödül: geçen gün durumu Hala yeni cevaplar aldı. Eğer cevap kadar gelmezse, Müslüman Ben Dhaou için ödül vermek zorunda kalacağım.
CEVAP
Derleyici uyarı ile VB.NET daha iyi bir şey yok sanırım, ama yine de o kadar ileri gideceğini sanmıyorum. "Doğru olanı" belki de potansiyel olarak faydalı bir şey(kovaryant veya karşıtı iki genel tür parametreleri ile aynı arayüz uygulama) izin vermeme ya da bir dili yeni tanıtımı gerektirir. ne yazık ki,
Bu haliyle, derleyici bir hata şimdi HungryWolf
sınıfı dışında atama diye bir yer yok. Bu bir sınıf belirsiz olabilecek bir şey yapmak için iddia ediyor noktasıdır. Gerektiğini söylüyorlar
Ben ** 28 ya da bir şey yemek için nasıl devralmasını uygulanması, belli bir şekilde.
Ve, ben de ** 29, ya da bir şey ya da uygulama miras yemek için biliyorum, belli bir şekilde.
Ancakhiçbir zaman ne yapması gerektiğini belirtireğer plaka üzerinde bir şey alırsahem bir ICloneable
IConvertible
. Bu ise kesin olarak söylemek için HungryWolf
, bir örnek verilirse, derleyici dert değil"Hey, burada ne yapacağımı bilmiyorum!". Ama ICanEat<string>
örnek olarak verildiğinde, derleyici keder verecek.Derleyici bu değişken nesnenin gerçek türü nedir, sadece kesinlikle ICanEat<string>
uygulamak hiçbir fikrim var.
HungryWolf
bir değişken içinde saklanır ne yazık ki, ne olduğu belirsiz, iki kez aynı arabirimi kullanır. Yani şüphe yok ki, biz al bir hata aramaya ICanEat<string>.Eat(string)
, Bu yöntem var ve olabilir son derece geçerli pek çok diğer nesneler olabilir içine yerleştirilmiş ICanEat<string>
değişken (batwad bahsedildiği bu onun cevapları).
Derleyici ICanEat<string>
değişken HungryWolf
bir nesne atama belirsiz şikayetçi olabilir, ancak daha ileri, iki adım olmasına engel olamaz. HungryWolf
bir diğer yöntem içine etrafında geçti olabilir ICanEat<IConvertible>
bir değişkene atanmış ve sonunda ICanEat<string>
bir değişkene atanabilir.Bunların her ikisi de tamamen yasal atamalarıve derleyici ya da bir şikayet için imkansız olurdu.
BöyleceBirinci seçenekICanEat<IConvertible>
ICanEat
ICanEat<ICloneable>
'In genel tür parametre bu iki arabirim birleştirmek olabilir çünkü karşıtı. her iki uygulama HungryWolf
sınıfı vermemek için. Ancak, bubir kod için yeteneği yararlı kaldırıralternatif bir çözüm ile.
İkinci seçenekmaalesefderleyici için bir değişiklik yapılması gerekirIL ve CLR. HungryWolf
sınıf iki arabirim uygulamak için izin verecek, ama aynı zamanda genel tür parametresi her iki arabirimleri uygulayan arayüzü ICanEat<IConvertible & ICloneable>
arayüzü, uygulanması gerekir. Bu büyük olasılıkla en iyi sözdizimi (Eat(T)
bu yöntem imzası neye benziyor, Eat(IConvertible & ICloneable food)
?) değil. Büyük olasılıkla, daha iyi bir çözüm otomatik olarak oluşturulan sınıf tanımının bir şey olurdu ki, uygulama sınıfı üzerine genel bir tür gibi: bir olacaktır
class HungryWolf:
ICanEat<ICloneable>,
ICanEat<IConvertible>,
ICanEat<TGenerated_ICloneable_IConvertible>
where TGenerated_ICloneable_IConvertible: IConvertible, ICloneable {
// implementation
}
IL sonra arayüz uygulama şekilleri callvirt
bir öğretim için genel sınıflar gibi inşa edilmesine izin edebilmek için değişmiş olurdu:
.class auto ansi nested private beforefieldinit HungryWolf
extends
[mscorlib]System.Object
implements
class NamespaceOfApp.Program/ICanEat`1<class [mscorlib]System.ICloneable>,
class NamespaceOfApp.Program/ICanEat`1<class [mscorlib]System.IConvertible>,
class NamespaceOfApp.Program/ICanEat`1<class ([mscorlib]System.IConvertible, [mscorlib]System.ICloneable>)!TGenerated_ICloneable_IConvertible>
CLR olur sonra süreci callvirt
talimatları tarafından inşa arayüzü uygulaması HungryWolf
string
olarak genel tür parametresi için TGenerated_ICloneable_IConvertible
ve kontrol görmek maçlar diğerinden daha iyi arabirim uygulamaları.
Kovaryans için, tüm bu ekstra arabirimleri uygulanması gereken kısıtlamaları ile genel türde parametreler olmak zorunda değil beri daha basit olurduama sadece iki diğer türleri arasında en türev temel türüderleme zamanında bilinen.,
Eğer aynı arayüzü uygulanır katından fazla, sonra sayı fazladan gerekli arayüzler için uygulanan katlanarak büyür, ama bunun maliyeti esnekliği ve tür güvenliği uygulama birden çok karşıtı(veya kovaryant) bir tek sınıf.
Sanmam bu olacak bulunun çerçevesinde, ama benim tercih edilen çözüm, özellikle bu yana yeni bir dil karmaşıklığı ki her zaman kendi kendine yeten bir sınıf olan dilek ne ise şu anda tehlikeli.
düzenleme:
Teşekkür ederim bana bunu hatırlattığın için 71**kovaryans contravariance daha kolaydırortak arayüzleri de dikkate alınması gerektiği gerçeğini nedeniyle. string
char[]
set halinde en büyük ortak{object
, , *ICloneable
*62} (63* *olur olurkaplı64**).
Ancak, bu arayüz genel türü için yeni bir sözdizimi parametre kısıtlaması, genel tür parametresi, yalnızca ihtiyacı olduğunu belirtmek gerekir
- belirtilen sınıf veya bir sınıf belirtilen arabirimler en az bir uygulama devralır
- belirtilen arabirimler en az birini uygulamak
Muhtemelen gibi bir şey
interface ICanReturn<out T> where T: class {
}
class ReturnStringsOrCharArrays:
ICanReturn<string>,
ICanReturn<char[]>,
ICanReturn<TGenerated_String_ArrayOfChar>
where TGenerated_String_ArrayOfChar: object|ICloneable|IEnumerable<char> {
}
Genel tür parametre TGenerated_String_ArrayOfChar
bu durumda(bir veya daha fazla arabirim ortak) her zaman tedavi olarak object
olsa bile, ortak bir temel sınıf var zaten türetilmiş object
; çünküsık görülen ortak temel sınıfından miras olmadan ortak bir arayüz uygulayabilir.
Neden Python (veya herhangi bir sabit ...
Ben ADT neden hata " alıyorum yükl...
Neden&; Sunucusu için ağ ile ilgili ve...
XML:teminatsız veya yanlış hatası hata...
Nasıl OS X çalışma zamanı veya iOS (Ge...