2010-01-15 17 views
5

Może to wydawać się rodzajem "zadania domowego" i/lub banalnym, ale ma to prawdziwy cel biznesowy; to tylko najłatwiejszy sposób, w jaki mógłbym wyjaśnić, co konceptualnie próbuję zrobić.Identyfikacja wyprowadzonych typów z listy obiektów klasy bazowej

Załóżmy, że mam klasę zwierząt i kilka innych klas (ptak, kot, kangur). Każdy z tych dziedziczy od Animal.

zwierząt może wyglądać następująco:

public class Animal 
{ 
    public Animal() 
    { 

    } 

    public string Name { get; set; } 
    public string AnimalType { get; set; } 
    public List<Animal> Friends { get; set; } 
} 

Kangur może wyglądać następująco:

public class Kangaroo : Animal 
{ 
    public Kangaroo() 
    { 

    } 

    public int TailLengthInches { get; set; } 
} 

Załóżmy, że kangur ma dwóch przyjaciół, ptak i kota. W jaki sposób mogę dodać je do listy "Zwierząt" (jak typ Animal), ale zachować możliwość dostępu do właściwości klas pochodnych? (Na przykład, wciąż muszę mieć możliwość pracy z właściwościami, które są specyficzne dla danego zwierzęcia, np. FeatherColor dla ptaka, chociaż będą uważane za "zwierzęta" .

Powód I Próbuję to zrobić, gdy później otrzymam listę "przyjaciół" zwierzęcia, ważne jest, aby wiedzieć, jaki rodzaj zwierzęcia jest przyjacielem. W zależności od typu zwierzęcia (czy to ptak, kot itp.) Chcę zrobić coś innego (pokażę inny szablon na stronie ASP.NET, ale nie potrzebuję konkretnej pomocy).

Chyba to sprowadza się do tego ... jeśli mam listę zwierząt, skąd mam wiedzieć, jaki był typ wyprowadzony dla każdego z obiektów na liście, więc mogę odrzucić je do ich typu pochodnego lub zrobić coś innego w pozwala mi dostać się do konkretnych, różnych właściwości, które są na każdym typie pochodnym?

Dzięki!

+1

Wskazówka: Aby otrzymać kod, aby wyświetlić poprawnie, użyj przycisku 101010 w edytorze (lub tiret czterema spacjami) . – itowlson

Odpowiedz

7

Można użyć LINQ do filtrowania typu, którego szukasz

animals.Friends = new List<Animal> { new Kangaroo(), new Bird() }; 
foreach (var kangaroo in animals.Friends.OfType<Kangaroo>()) { 
    kangaroo.Hop(); 
} 
+0

To naprawdę elegancki sposób na obsługę. Dzięki! –

1

Spróbuj przesłać go:

var friendBird = friend as Bird; 
if (friendBird != null) 
{ 
    // It's a bird, so do something with it 
) 
+0

+1 za używanie słowa kluczowego 'as' w celu uniknięcia podwójnego rzucenia związanego ze słowem kluczowym' is', a następnie rzucania obiektu. –

1

Można użyć typeof uzyskać rzeczywisty typ lub użyj is lub as operatorom testowania i ewentualnie obsada:

foreach (Animal a in Friends) 
{ 
    Kangaroo k = a as Kangaroo; 
    if (a != null) 
    { 
    // it's a kangaroo 
    k.JumpAround(); 
    } 
    Ostrich o = a as Ostrich; 
    if (o != null) 
    { 
    o.StickHeadInSand(); 
    } 
} 

(nie mam używane tutaj klauzule else, które mogą powodować błędy, jeśli testujesz typy, które mogą znajdować się w hierarchii, np. jeśli masz zarówno klauzule Kangaroo i Marsupial, prawdopodobnie NIE chciałbyś, aby oba zostały wykonane!)

Można to zrobić także z operatorem is, który wygląda ładniej, ale uczyni FxCop cry:

foreach (Animal a in Friends) 
{ 
    if (a is Kangaroo) 
    { 
    ((Kangaroo)a).JumpAround(); 
    } 
} 

w ogóle, nawiasem mówiąc, prawdopodobnie chcesz szukać okazji postawić wirtualną metodę na Animal i implementuj tę metodę polimorficznie, zamiast monstrualnych instrukcji if, które powodują kruche połączenie ze specyficznym zbiorem klas pochodnych.

0

Użyj słowa kluczowego "jest".

jeśli (zwierzę jest ptakiem) ...

0
animals.Friends = new List<Animal> { new Kangaroo(), new Bird() }; 
foreach (Animal animal in animals.Friends) 
{ 
if (animal is Kangaroo) 
Console.WriteLine("Kangaroo"); 
else if (animal is Bird) 
Console.WriteLine("Bird"); 
} 
Powiązane problemy