2015-06-22 5 views
6

Meine Situation:Unconstrained Parameter Art Casting

interface ISomeInterface { 
    void DoSmth<T>(T other); 
} 

class Base : ISomeInterface 
{ 
    public virtual void DoSmth<T>(T other){ 
     // for example do nothing 
    } 
} 

class Derived<T2> : Base { 
    Action<T2> MyAction {get;set;} 

    public override void DoSmth<T>(T other){ 
     if(typeof(T2).IsAssignableFrom(typeof(T))) 
      MyAction((T2) other); 
    } 
} 

Das gibt mir eine Fehlermeldung: Cannot cast expression of type 'T' to type 'T2' (oder Cannot convert type 'T' to 'T2')

Ich verstehe, dass es ist, weil weder T oder T2 mit class eingeschränkt sind, aber wenn ich weiß ich - wegen IsAssignableFrom - dass ich T verwenden kann, wo ich T2 brauche, wie kann ich Compiler davon überzeugen, es zu erlauben?

+3

'(T2) (Objekt) andere' – PetSerAl

+3

' (T2) (Objekt) andere' – leppie

+0

Yup, ihr habt recht - ich habe diese Idee nur Sekunden nach dem Posten;) Schreibe eine Antwort und ich akzeptiere es:) – Gerino

Antwort

3

Der Compiler sieht die T2 und T Bezeichner und informiert Sie hilfreich, dass diese Typen nicht verwandt scheinen. Das ist absolut richtig, da sie keine Beziehung haben: es gibt keine generischen Einschränkungen, die irgendwelche Beziehungen zwischen ihnen behaupten würden (ich sage nicht, dass das hier aber nützlich wäre :)).

Ob dies eine gute Funktion ist oder nicht, ist fraglich. Manchmal möchte ich, dass es nur eine Warnung ist, aber in den meisten Fällen ist es hilfreich, wenn es ein Kompilierungsfehler ist. Die Anzahl solcher Casts in generischen Klassen ist viel niedriger als die Anzahl der Tippfehler im 'normalen' Code :)

Lösung ist sehr, sehr einfach. betrüge nur die Compiler nichts über die Quelle Typen zu kennen, und es wird die Typhierarchie prüft gegen Zieltyp Überspringen:

T theTee = ...; 
object temp = (object)theTee; 
T2 teeTwo = (T2)temp; // ok! 'temp' is now seen as 'object' 

oder in Motto:

T2 teeTwo = (T2)(object)theTee; 

ähnlich, können Sie dynamic (wenn es an Ihrer .Net-Version verfügbar ist):

T theTee = ...; 
dynamic temp = theTee; 
T2 teeTwo = temp; 

und oneliner sollte auch funktionieren:

T2 teeTwo = (dynamic)theTee; 

obwohl ich das nie probiert habe, wie ich denke, es ist schwerer als Cast-via-Objekt. Ich habe jedoch die Leistung von Objekt/dynamischen Ansätzen nicht überprüft. Nur eine Ahnung.

+0

Als ich meine erste über Dynamik gelesen habe, ist es wahrscheinlich schlechter in Bezug auf die Leistung. Ich denke, ich werde (T2) (Objekt) wählen - ich habe einen Kommentar hinzugefügt, der mich zu "zukünftigen Generationen" erklärt. Wenn ich es nur nach 'IsAssignableFrom == true' mache, sollte es immer funktionieren, oder? – Gerino

+1

Soweit ich mich erinnere, ist 'IsAssignableFrom' die beste Typ-gegen-Typ-Prüfung, die Sie bekommen können. Von Zeit zu Zeit stört mich der Name 'IsAssignableFrom' gegenüber' IsCastable'. Ich kann mich an keinen Fall erinnern, wenn 'AssignableFrom' nicht' Castability' verursachen würde. Ich kann dir nicht sagen, dass ich mir absolut sicher bin. Ich kann mir einige sehr seltene Fälle vorstellen, in denen etwas Seltsames passieren könnte, aber ich sehe und erinnere mich an keinen Fall, in dem es nicht funktionieren würde. – quetzalcoatl

+1

@Gerino: Also, ich bin fest davon überzeugt, dass "IsAssignableFrom" "Casability" bedeutet, in diese Richtung. Diese Bedingungen sind jedoch nicht gleich. Ich glaube *, dass 'IsAssignableFrom' Ihnen zumindest einige ** falsche Negative ** bringen kann. Zum Beispiel kann ein '__ComObject' zur Laufzeit auf Schnittstellen umgewandelt werden, aber ich glaube nicht, dass der Typ 'IsAssignableFrom' in diese Schnittstellentypen gehört. Aber nie überprüft. Könnte interessant sein, MSDN Artikel für diesen Fall zu überprüfen. – quetzalcoatl