2014-04-25 6 views
6

Próbuję napisać metodę rozszerzenia, który sprawdza, czy dany przedmiot jest sub klasy T.metodę rozszerzenia, aby sprawdzić, czy obiekt jest sub klasy T

Oto co zrobiłem, ale nie są akceptowane przez visual studio .

public static bool IsChildOf<T>(this object obj) 
{ 
    return (typeof(obj).IsSubclassOf(typeof(T))); 
} 

[Test()] 
public void IsChildOfTest() 
{ 
    var dog = new Dog(); 
    var isAnimal = dog.IsChildOf<Animal>(); 
    Assert.That(isAnimal); 
} 

Każdy pomysł, jak mogę to napisać?

+1

marginesie: „klasa dziecko” i terminy „klasa dominująca” są zniechęceni. Zamiast tego powinieneś powiedzieć "pochodzi z". Samochód nie jest dzieckiem pojazdu; samochód wywodzi się z pojazdu. Zamiast tego nazwałbym twoją metodę "DerivesFrom ". – dcastro

+0

Zgadzam się. Zarezerwuj terminy dziecko/rodzic dla relacji "ma", a nie "jest". Zwłaszcza na listach lub relacjach rekurencyjnych, takich jak drzewa. – weston

+0

Komentarze: 'typeof (X)' wymaga, aby 'X' był typem (jak twoje' T'), a nie wartością lub wyrażeniem (jak twoje 'obj'). Czy wiesz, że 'IsSubclassOf' ma wartość false, jeśli jeden z typów jest interfejsem lub typem wartości i czy te dwie klasy są identyczne? Może chciałeś 'IsAssignableFrom'? Prawdopodobnie łatwiejsze jest użycie słowa kluczowego C# 'is'. Zobacz odpowiedź Westona. –

Odpowiedz

6

można po prostu użyć is. Ale uwaga, że is nie robi dokładnie tak samo jak IsSubclassOf. Zobacz doskonały komentarz Jeppe dla szczegółów i mam też przykład poniżej.

Na marginesie, nie sądzę, że Java pozwala na równoważne instanceof w takim ogólnym przypadku z jakiegoś powodu, ale jest OK w C#. Tj .:

public static bool IsChildOf<T>(this object obj) 
{ 
    return obj is T; 
} 

Wtedy to czyni go tak trywialne, że jest to bardziej skomplikowane, aby czytelnicy w użyciu metodę rozszerzenia niż is bezpośrednio. Jeśli go stosować bezpośrednio nasz test będzie wtedy wyglądać tak:

[Test()] 
public void IsChildOfTest() 
{ 
    var dog = new Dog(); 
    var isAnimal = dog is Animal; 
    Assert.That(isAnimal); 
} 

Przykładem jednej z różnic między is i IsSubclassOf:

[Test] 
public void IsChildOfTest() 
{ 
    var dog = new Dog(); 
    Assert.False(dog.GetType().IsSubclassOf(typeof(Dog))); 
    Assert.True(dog is Dog); 
} 
+3

Wznowienie dla wzmianki o "jest". Nie jest to dokładnie odpowiednik 'Type.IsSubclassOf'. Niektóre różnice: Jeśli 'T' jest * tą samą klasą *, co typ biegu' obj', 'jest' mówi' true', a 'IsSubclassOf' mówi' false'. Jeśli 'T' jest interfejsem,' is' sprawdza, czy 'obj' reprezentuje' interfejs', podczas gdy 'IsSubclassOf' mówi" fałsz ". Jeśli typem wykonania "obj" jest typ wartości (boxed), 'is' sprawdza się zgodnie z oczekiwaniami, podczas gdy' IsSubclassOf' mówi "nie". 'jest' także bierze pod uwagę ko- i contrawariancję w generykach, na przykład coś, co jest" IEnumerable "jest także" IEnumerable "(patrz' IEnumerable '). –

+0

@Jeppe Stig Nielsen, bardzo dobry punkt, że nie jest równoważny. Dobrze to wyjaśnić w przypadku nieporozumień. I rzeczywiście, pomimo proponowanej nazwy IsChildOf, PO może nie zamierzać tych różnic. –

+0

@JeppeStigNielsen Dzięki, to dużo ważnych informacji, które przegapiłem!Sądzę, że 'is' jest równoważne' Type.IsAssignableFrom' – weston

6

Zastosowanie GetType zamiast typeof kiedy trzeba instancję typu:

public static bool IsChildOf<T>(this object obj) 
{ 
    return (obj.GetType().IsSubclassOf(typeof(T))); 
} 
5
public static Boolean IsChildOf<T>(this Object obj) 
{ 
    // Don't forget to handle obj == null. 
    return obj.GetType().IsSubclassOf(typeof(T)); 
} 
+0

Proste wyrażenie "obj to T" nie eksploduje, jeśli "obj" ma wartość "null" (po prostu zwraca wartość "false"). Zobacz inne zalety 'jest' w moim komentarzu do odpowiedzi Westona. –

2
public static bool IsChildOf<T>(this object obj) 
    { 
     return obj != null && (obj.GetType().IsSubclassOf(typeof(T))); 
    } 

również użyć Assert.IsTrue w miejsce Assert.That