2013-04-06 15 views
31

Ich habe eine Erweiterungsmethode zum sicheren Gussobjekte, die wie folgt aussieht:IsAssignableFrom, IsInstanceOfType und das Schlüsselwort is, was ist der Unterschied?

public static T SafeCastAs<T>(this object obj) { 
    if (obj == null) 
     return default(T); 

    // which one I should use? 

    // 1. IsAssignableFrom 
    if (typeof(T).IsAssignableFrom(obj.GetType())) 
     return (T)obj; 

    // 2. IsInstanceOfType 
    if (typeof(T).IsInstanceOfType(obj)) 
     return (T) obj; 

    // 3. is operator 
    if (obj is T) 
     return (T) obj; 

    return default(T); 
} 

Wie Sie sehen können, habe ich 3 Wahl, so das man sollte ich verwenden? Was ist eigentlich der Unterschied zwischen IsAssignableFrom, IsInstanceOfType und is Operator?

Antwort

42

Sie verwenden, was Sie für die Informationen haben.

Wenn Sie eine Instanz und einen statischen Typ haben, mit denen Sie überprüfen möchten, verwenden Sie is. Wenn Sie nicht den statischen Typ haben, haben Sie nur ein Type Objekt, aber Sie haben eine Instanz, die Sie überprüfen möchten, verwenden Sie IsInstanceOfType. Wenn Sie keine Instanz haben und nur die Kompatibilität zwischen einer theoretischen Instanz einer Type und einer anderen Type überprüfen möchten, verwenden Sie .

Aber es scheint, als ob Sie nur die as operator re-implementieren (außer dass Ihre auch für nicht-Nullable Werttypen arbeiten würde, die in der Regel keine große Einschränkung ist).

9

Ich denke, Sie implementieren effektiv eine Version des as-Operators, der mit Werttypen sowie Referenztypen arbeitet.

würde ich gehen für:

public static T SafeCastAs<T>(this object obj) 
{ 
    return (obj is T) ? (T) obj : default(T); 
} 

IsAssignableFrom Arbeiten mit Typen und is Arbeiten mit Instanzen. Sie werden Ihnen die gleichen Ergebnisse in Ihrem Fall geben, also sollten Sie die einfachste Version IMHO verwenden.

Wie für IsInstanceOfType: Das ist in Bezug auf IsAssignableFrom implementiert, so wird es keinen Unterschied geben.

Sie können beweisen, dass durch Reflector bei der Definition von IsInstanceOfType() suchen mit:

public virtual bool IsInstanceOfType(object o) 
{ 
    if (o == null) 
    { 
     return false; 
    } 
    return this.IsAssignableFrom(o.GetType()); 
} 
3

Ich denke, Sie sollten einfach mit "as" statt Ihrer benutzerdefinierten "SafeCastAs" gehen. Aber das funktioniert nur für Klassen (nicht Strukturen), also wenn Sie diese Methode auch für Strukturen verwenden wollen, kann ich es bekommen.

Operator "ist" gibt Ihnen grundsätzlich das gleiche wie Type.IsAssignableFrom, so dass Sie nur "is" behalten können, es prüft, ob Sie obj ohne Ausnahme zu T sicher zu werfen. Es deckt also beide vorherigen Prüfungen in Ihrer Methode ab. Sie sollten sich jedoch darüber im Klaren sein, dass es nicht prüft, ob Sie aufgrund benutzerdefinierter Konvertierungen obj T zuordnen können: explicit und implicit Keywords.

+0

Ich bin mir nicht sicher, Ihre Behauptung hier ist richtig. 'typeof (int)' gibt ein Objekt vom Typ 'Type' zurück, so dass die erste Anweisung fehlschlägt, da dieses' Type'-Objekt offensichtlich kein 'int' ist. Wenn Sie jedoch die erste Anweisung in 'a.GetType() ändern. IsInstanceOfType (3)' wird True zurückgegeben. Ich denke, dass Sie "IsInstanceOfType" falsch hier verwenden. –

+0

@JeffBridgman wahr, meine Vermutung Ich habe gerade versucht, den Unterschied der Verwendung dieser beiden Methoden zu zeigen, etwas wie '' ' Console.WriteLine (typeof (int?). IsInstanceOfType (null)); Console.WriteLine (typeof (int?). IsInstanceOfType (1)); Console.WriteLine (typeof (int?). IsAssignableFrom (typeof (int))); '' ' Ich werde einige Teile dieser Antwort entfernen. – outcoldman

0

Diese Funktionen und Operatoren haben unterschiedliche Bedeutung. Wenn Sie Objekte haben, können Sie immer Typen erhalten. Sie arbeiten also nicht an dem, was Sie haben, sondern Sie tun, was getan werden muss.

Wenn Sie mit einer Klassenhierarchie arbeiten, sind die Unterschiede sehr deutlich.

Schauen Sie sich beispielsweise folgende

 class ABase 
     { 

     } 

     class BSubclass : ABase 
     { 

     } 
    ABase aBaseObj = new ABase(); 
       BSubclass bSubclassObj = new BSubclass(); 

       ABase subObjInBaseRef = new BSubclass(); 

Verschiedene Operationen führen zu unterschiedlichen Ergebnissen.

typeof(ABase).IsInstanceOfType(aBaseObj) = True 

typeof(ABase).IsInstanceOfType(bSubclassObj) = True 

typeof(ABase).IsInstanceOfType(bSubclassObj) = True 

typeof(BSubclass).IsInstanceOfType(aBaseObj) = False 

bSubclassObj is ABase = True 

aBaseObj is BSubclass = False 

subObjInBaseRef is BSubclass = True 

subObjInBaseRef is BSubclass = True 

typeof(ABase).IsAssignableFrom(typeof(BSubclass)) = True 

typeof(BSubclass).IsAssignableFrom(typeof(ABase))= False 

Im Fall auf keine Hierarchie, könnte alles gleich sein. Aber wenn Sie mit Hierarchie, IsAssignableFrom arbeiten, ist, und IsInstanceOfType ergeben unterschiedliche Ergebnisse.

Es gibt mehrere mögliche Kombinationen, die ausprobiert werden könnten. Zum Beispiel können Sie in diesem Beispiel eine Klasse C einführen, die in keiner Weise mit bestehenden Klassen verwandt ist.

Verwandte Themen