2013-04-06 13 views
31

Mam metodę rozszerzenia do bezpiecznych obiektów odlewniczych, które wygląda następująco:IsAssignableFrom, IsInstanceOfType i jest słowem kluczowym, jaka jest różnica?

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); 
} 

Jak widać, mam 3 wybór, więc który z nich powinienem użyć? Czym właściwie różni się operator IsAssignableFrom, IsInstanceOfType i is?

Odpowiedz

42

użyć cokolwiek ma informacje dotyczące.

Jeśli masz instancję i typ statyczny, który chcesz sprawdzić, użyj is.

Jeśli nie masz statycznego typu, po prostu masz obiekt Type, ale masz instancję, którą chcesz sprawdzić, użyj IsInstanceOfType.

Jeśli nie masz instancji i chcesz tylko sprawdzić kompatybilność między teoretyczną instancją obiektu Type i innym Type, użyj IsAssignableFrom.

Ale tak naprawdę wygląda na to, że po prostu ponownie wdrażasz as operator (oprócz tego, że twój będzie również działać dla nie-zerowalnych typów wartości, co zwykle nie jest dużym ograniczeniem).

9

Domyślam się, że skutecznie wdrażasz wersję operatora as, która działa z typami wartości oraz typami odwołań.

pójdę do:

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

IsAssignableFrom prac z rodzajami i is prac z instancji. Dadzą ci takie same wyniki w twoim przypadku, więc powinieneś użyć najprostszej wersji IMHO.

Jeśli chodzi o IsInstanceOfType: To jest realizowane pod względem IsAssignableFrom, więc nie będzie różnicy.

Można udowodnić, że za pomocą reflektor spojrzeć na definicję IsInstanceOfType():

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

Chyba powinieneś po prostu użyć "as" zamiast niestandardowego "SafeCastAs". Ale to będzie działać tylko dla klas (nie struktur), więc jeśli chcesz użyć tej metody również dla struktur, mogę ją uzyskać.

Operator "jest" w zasadzie daje to samo, co Type.IsAssignableFrom, więc możesz zachować tylko "jest", sprawdza, czy możesz bezpiecznie rzucić obj do T, bez wyjątków. Obejmuje to zarówno wcześniejsze kontrole w twojej metodzie. Należy jednak mieć świadomość, że nie sprawdza, czy można przypisać obj do T, ze względu na zdefiniowane przez użytkownika konwersje: explicit i implicit słów kluczowych.

+0

Nie jestem pewien, czy twoje stwierdzenie tutaj jest poprawne. 'typeof (int)' zwraca obiekt typu 'Type', więc pierwsza instrukcja zakończy się niepowodzeniem, ponieważ obiekt' Type' nie jest oczywiście 'int'. Jednak jeśli zmienisz pierwszą instrukcję na 'a.GetType(). IsInstanceOfType (3)' zwróci ona true. Myślę, że używasz tutaj "IsInstanceOfType". –

+0

@JeffBridgman prawda, zgaduję, że próbowałem pokazać różnicę w użyciu tych dwóch metod, coś w rodzaju '' ' Console.WriteLine (typeof (int?). IsInstanceOfType (null)); Console.WriteLine (typeof (int?). IsInstanceOfType (1)); Console.WriteLine (typeof (int?). IsAssignableFrom (typeof (int))); '' ' Zamierzam usunąć niektóre części tej odpowiedzi. – outcoldman

0

Te funkcje i operatory mają różne znaczenie. Jeśli masz obiekty, zawsze możesz otrzymać typy. więc nie pracujesz nad tym, co masz, ale robisz to, co musisz zrobić.

Podczas pracy z hierarchią klas różnice są bardzo wyraźne.

wygląd w następujący przykład

 class ABase 
     { 

     } 

     class BSubclass : ABase 
     { 

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

       ABase subObjInBaseRef = new BSubclass(); 

różnych operacji dawać różne wyniki.

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 

W przypadku braku hierarchii wszystko mogło być takie samo. Ale jeśli pracujesz z hierarchią, IsAssignableFrom, jest i IsInstanceOfType przynosi różne wyniki.

Istnieje więcej możliwych kombinacji, które można wypróbować. Na przykład możesz wprowadzić klasę C, która nie jest w żaden sposób powiązana z istniejącymi klasami w tym przykładzie.

Powiązane problemy