2012-12-03 19 views
6

Rozejrzałem się po kilku, aby znaleźć rozwiązanie tego problemu. Znalazłem kilka sposobów na rozwiązanie tego problemu, ale szczerze mówiąc, nie zdawałem sobie sprawy z tego, który ze sposobów byłby uważany za "właściwy" sposób C# lub OOP rozwiązania. Moim celem jest nie tylko rozwiązanie problemów, ale także opracowanie dobrego zestawu standardów kodowych i jestem pewien, że istnieje standardowy sposób rozwiązania tego problemu.C# Obiekty różnych klas w jednej liście

Załóżmy, że mam 2 rodzaje drukarek do drukarek z ich odpowiednimi klasami i sposobami komunikowania się: PrinterType1, PrinterType2.

Chciałbym również móc później dodać inny typ, jeśli jest to konieczne. Jeden krok w abstrakcji mają wiele wspólnego. Powinno być możliwe wysłanie ciągu znaków do każdego z nich jako przykładu. Oba mają zmienne wspólne i zmienne unikalne dla każdej klasy. (Jeden na przykład komunikuje się przez port COM i ma taki obiekt, podczas gdy drugi komunikuje się przez TCP i ma taki obiekt).

Chciałbym jednak po prostu zaimplementować listę wszystkich tych drukarek i móc przeglądać listę oraz wykonywać czynności jako "Wyślij (wiadomość tekstową)" we wszystkich drukarkach niezależnie od ich typu. Chciałbym również uzyskać dostęp do zmiennych takich jak "PrinterList [0] .Name", które są takie same dla obu obiektów, jednak chciałbym również w niektórych miejscach, aby uzyskać dostęp do danych, które są specyficzne dla samego obiektu (na przykład w oknie ustawień aplikacja, dla której ustawiono nazwę portu COM dla jednego obiektu i numer IP/port dla innego obiektu).

Więc, krótko mówiąc coś podobnego:

wspólne:

  • Nazwa
  • send()

specyficzne dla PrinterType1:

  • Port

Specific do PrinterType2:

  • IP

i pragnę, na przykład, nie Send() na wszystkich obiektach, niezależnie od rodzaju i liczby obiektów obecnych.

Czytałem o polimorfizm, generics, interfejsy i takie, ale chciałbym wiedzieć, jak to, w moich oczach podstawowe, problem zazwyczaj będzie rozpatrywane w C# (i/lub OOP w ogóle).

Właściwie to próbowałem zrobić klasę podstawową, ale nie wydawało mi się to właściwe. Na przykład nie używam funkcji "string Send (string Message)" w samej klasie bazowej. Więc dlaczego miałbym zdefiniować taki, który musi zostać nadpisany w klasach pochodnych, kiedy nigdy nie używałbym tej funkcji w klasie bazowej w ogóle?

Jestem naprawdę wdzięczny za wszelkie odpowiedzi. Ludzie tutaj wydają się bardzo kompetentni i to miejsce wcześniej dostarczyło mi wielu rozwiązań. Teraz mam wreszcie konto, na które trzeba odpowiedzieć i zagłosować.

EDIT:

Aby dodatkowo wyjaśnić, chciałbym również, aby móc uzyskać dostęp do obiektów rzeczywistych printertype. Na przykład zmienna Port w PrinterType1, która jest obiektem SerialPort. Chciałbym uzyskać do niego dostęp, takich jak: PrinterList[0].Port.Open()

i mieć dostęp do pełnego zakresu funkcjonalności pod nią portu. Jednocześnie chciałbym wywołać funkcje rodzajowe, które działają w ten sam sposób dla różnych obiektów (ale z różnymi implementacjami):

foreach (printer in Printers) 
    printer.Send(message) 
+0

Proponuję, w zależności od tego, które rozwiązanie będzie używane w tym konkretnym przypadku, wybierasz dobrą książkę o podstawach OOP. Dobra książka również dostarczy przykłady i na pewno zobaczysz KIEDY i JAK używać każdej funkcji języka, którą wybierzesz. –

+0

+1. Chcąc opracować dobry zestaw standardów kodowych. –

Odpowiedz

9

a Pseudo-przykład przy użyciu interfejsów.

public interface IPrinter 
{ 
    void Send(); 
    string Name { get; } 
} 

public class PrinterType1 : IPrinter 
{ 
    public void Send() { /* send logic here */ } 
    public string Name { get { return "PrinterType1"; } } 
} 

public class PrinterType2 : IPrinter 
{ 
    public void Send() { /* send logic here */ } 
    public string Name { get { return "Printertype2"; } } 

    public string IP { get { return "10.1.1.1"; } } 
} 


// ... 
// then to use it 
var printers = new List<IPrinter>(); 

printers.Add(new PrinterType1()); 
printers.Add(new PrinterType2()); 

foreach(var p in printers) 
{ 
    p.Send(); 

    var p2 = p as PrinterType2; 

    if(p2 != null) // it's a PrinterType2... cast succeeded 
    Console.WriteLine(p2.IP); 
} 
+0

Dziękuję za bardzo dobrą i szybką sugestię. Powiedzmy, że zmienną IP zdefiniowaną w PrinterType2 był obiekt portu SerialPort, który chciałbym edytować, czy mógłbym uzyskać do niego bezpośredni dostęp? Port.Dispose(), Port.Nazwa(), Port.Open() itp. –

+0

Interfejs ujawnia jedynie metody/właściwości, które deklaruje. Jeśli masz kolekcję obiektów IPrinter, musisz określić, czy konkretna instancja była rzeczywiście instancją PrinterType2, a następnie poprawnie ją rzucić. (Można to zrobić za pomocą operatorów ** jest ** i ** jako **). – ThatBlairGuy

+0

Tak więc, jeśli jedna klasa ma obiekt Port, a jedna nie, a ja wypełniam Listę z 2 obiektami: Jeden z PrinterType1 i jeden z PrinterType2. Tylko jeden z nich ma obiekt "Port". Jak mogę uzyskać do niego dostęp? Najprawdopodobniej czegoś tutaj brakuje, ale w powyższym kodzie nie widzę, w jaki sposób uzyskuję dostęp do obiektu, który jest obecny tylko w jednej z dwóch klas. Czy mówisz, że muszę sprawdzić typ członka listy, rzucić go na typ, jaki faktycznie jest (lub kiedy dodałem go do listy), a stamtąd dostęp i edytować rzeczywisty obiekt leżący u podstaw? –

2

Załóż interfejs (słownie IPrinterType), która posiada swoje „wspólne” metod i użyj tego interfejsu.

+0

Dziękuję za odpowiedź. Niektóre interfejsy zostały zbadane, ale z tego, co przeczytałem, nie można używać zmiennych w ten sposób. Muszę więc wprowadzić wszystkie zmienne do właściwości, które mi się nie podobają. Jest to jednak jedno rozwiązanie. –

0

Jakie są twoje opisy, do których interfejsów zostały zaprojektowane. Umieść w niej wszystkie wspólne właściwości/metody i ukryj konkretną implementację. Wciąż zalecałbym posiadanie klasy bazowej Printer, ponieważ oczywiście będzie podobny kod, który można udostępnić.

Jeśli chodzi o bardziej zdefiniowane właściwości, o których wspominasz np. Port/IP, musisz wiedzieć, z jakim typem masz do czynienia. W tym momencie możesz rzucić go we właściwy typ.

+0

Tak, to te bardziej zdefiniowane właściwości, w których mam najwięcej problemów z dopasowaniem gdzieś. Chciałbym uzyskać dostęp do obiektu (na przykład SerialPort), który jest obecny tylko w JEDNEJ z klas pochodnych. I chcę uzyskać do niego dostęp z klasy bazowej, ponieważ lista jest zdefiniowana z tego typu. –

+0

@jeah_wicer, więc jest to scenariusz, w którym musiałbyś rzucić go do tego konkretnego typu pochodnego, np. 'var castedObj = to jako DerivedType; if (castedObj! = null) {...} '. – James

2

Co szukasz jest abstrakcyjną klasą bazową, tak:

abstract class Printer 
{ 
    public string Name { get; set; } 
    public abstract string Send(string Message); 
} 

wtedy dziedziczą z tej klasy i realizować swoje Wyślij function() zgodnie z potrzebami.

Możesz również użyć interfejsu. Różnica polega na tym, że interfejs może określać jedynie właściwości, metody i zdarzenia, które musi implementować dziedziczyk - nie implementuje żadnego kodu. To, którego używasz, zależy od tego, co najlepiej pasuje do Twojej aplikacji. Możesz skończyć z wykonywaniem obu (tworzenie abstrakcyjnej klasy, która implementuje interfejs).

1

Dla konkretnego pytania "Na przykład nie używam funkcji" string Send (string Message) "w samej klasie bazowej, więc dlaczego miałbym zdefiniować taką, która musi być nadpisana w klasach pochodnych, gdy Nigdy w życiu nie skorzystałbym z tej funkcji w klasie bazowej? "

Naprawdę nie ma potrzeby wdrażania go w klasie bazowej.

Jeśli twoja klasa podstawowa jest klasą abstrakcyjną, możesz ją po prostu zadeklarować, a następnie pozostawić w konkretnych klasach, aby ją zaimplementować.

Jeśli nie chcesz dostarczać żadnych konkretnych implementacji, zamiast klasy abstrakcyjnej, możesz lepiej obsłużyć interfejs, do którego wdrożenia wymagane są wszystkie konkretne klasy.

Powiązane problemy