2010-12-20 5 views
2

Ich habe eine Funktion, die eine Signatur vonUngültiges Argument - Interfaces vererbt, wie funktioniert, implizites Casting nicht. Was gibt?

Update(IEnumberable<INotifyPropertyChanging> things) 

und eine Klasse

doohickey : INotifyPropertyChanging, INotifyPropertyChanging{} 

Wenn ich versuche zu tun

List<doohickey> doohickeys = new List<doohickey>(); 
Update(doohickeys); 

eine Ausnahme ausgelöst wird erklärt hat:

cannot convert from 'System.Collections.Generic.List<doohickey>' to 'System.Collections.Generic.IEnumerable<System.ComponentModel.INotifyPropertyChanging>' 

Was gibt? Doohickey erbt die INotifyPropertyChanging-Schnittstelle und List erbt die IEnumerable-Schnittstelle! Wie kommt es, wenn man einfach das Objekt passiert und erwartet, dass es niedergeschlagen wird?

Ich habe die Verweise auf INotifyPropertyChanging enthalten, um anzuzeigen, dass Doohickey eigentlich eine linq-to-sql-Klasse ist; falls dieses bisschen Kontext wichtig ist.

+0

Ich denke, es hat mit Kovarianz/Kontravarianz zu tun. Verwenden Sie C# 4? http://blogs.msdn.com/b/csharpfaq/archive/2010/02 /16/covariance-and-contravariance-faq.aspx –

+0

hast du _exception_ oder _compile error_? – Shrike

Antwort

3

Dies funktioniert nicht, da zwischen List<doohickey> und IEnumerable<NotifyPropertyChanging> keine implizite Konvertierung stattfindet. Sie müssen anrufen:

Update(doohickeys.Cast<INotifyPropertyChanging>()); 

Der Grund dafür ist Typ Sicherheit. In C# 4 wurde die Ko-/Kontravarianz zur Sprache hinzugefügt, was im Allgemeinen dazu beiträgt, dass diese Art von Konvertierungen gültig ist. Es gibt jedoch einige Einschränkungen, da der betreffende Typ co-/kontravariant deklariert werden muss und nur für Schnittstellen und Delegaten gilt.

Der Grund, warum Sie nicht implizit List<T>-List<TBase> umwandeln kann, ist, dass es diesen Code gültig machen würde:

List<T> values = new List<T>(); 
// add some values... 
List<TBase> bases = values; 
bases.Add(new TBase()); // Woops. We broke type safety by adding a TBase to a list of T's 

Nun, wenn Sie dies tun, wenn andere values von IEnumerable<T> Typ war, wäre es in C# 4 gültig sein. Dies liegt daran, dass Sie nur Werte von IEnumerable<T> erhalten können, so dass wir uns keine Sorgen um kleinere Typen machen müssen. Daher IEnumerable<T> ist covariant, und erklärt, wie:

IEnumerable<out T> 

Wo out bedeutet "covariant". (Die Schlüsselwörter ist eigentlich der beste Weg, sich daran zu erinnern, welche Art und Weise Werte in einer Variante Typ gehen.

Co-/Kontra ist ein ziemlich großes Thema, but this article does a good job of explaining the most important parts. Und wenn Sie mehr erfahren möchten, hat Eric Lippert eine 11-part blog post series über Eric ist einer der Sprachdesigner.

+0

Aus irgendeinem Grund dachte ich, dass Casting funktioniert, aber Casting funktioniert nicht.Es scheint die ganze Idee von "Codierung gegen eine Schnittstelle" gelenkig auf diese Idee in meinem Kopf, während die Lösung scheint nicht zu stumpf scheint immer noch nicht ideal. Ich brauche jetzt dieses .Cast () Zeug hängen von meinen Sachen ab, die meinem Code geistiger cruft hinzufügen. Seltsamerweise schien dies mein Problem zu lösen, aber es löschte ein anderes aus, wo ich mit System böse, böse, hässliche Dinge tat.Betrachtung. Vielen Dank für die äußerst wertvollen Informationen! – MushinNoShin

Verwandte Themen