2012-12-03 10 views
6

私は今この問題を解決するために何かを見てきました。私はそれを解決することができるいくつかの方法を見つけましたが、正直言って、それを解決する "正しい" C#またはOOPの方法と考えられる方法はわかりませんでした。私の目標は、問題を解決するだけでなく、コード標準の優れたセットを開発することでもあり、この問題を処理する標準的な方法があると確信しています。C#1つのリスト内の異なるクラスオブジェクト

私はそれぞれのクラスと通信方法で2種類のプリンタハードウェア、PrinterType1、PrinterType2を持っています。

また、必要に応じて後で別のタイプを追加することもできます。抽象化のステップアップは共通点が多い。例としてそれぞれの文字列に文字列を送ることが可能でなければなりません。彼らはどちらも共通の変数と各クラスに固有の変数を持っています。 (たとえば、COMポート経由で通信し、そのようなオブジェクトを持ち、もう一方はTCP経由で通信し、そのようなオブジェクトを持っています)。

しかし、私はこれらすべてのプリンタのリストを実装し、タイプに関係なく、リストを通過してすべてのプリンタで「送信(文字列メッセージ)」として実行することができます。私は両方のオブジェクトで同じ "PrinterList [0] .Name"のような変数にアクセスしたいと思いますが、私はまた、オブジェクト自体に固有のデータにアクセスするような場所もあります(たとえば、 1つのオブジェクトにCOMポート名が設定され、別のオブジェクトにIP /ポート番号が設定されているアプリケーション)。一般的には

  • 名前
  • センド()PrinterType1に固有

:短い何かのようでそう

  • ポート
  • PrinterType2に固有

  • IP

そして、私は、例えば、種類及び存在するオブジェクトの数に関係なく、すべてのオブジェクトに()を送信しないことを望みます。

多型性、ジェネリックス、インターフェイスなどについて私は読んだことがありますが、私の目では基本的にこの問題がC#(および/または一般的なOOP)でどう対処されるのかを知りたいと思います。

私は実際に基本クラスを作ろうとしましたが、それは私にはあまりにも似ていませんでした。例えば、私は基本クラス自体に "文字列送信(文字列メッセージ)"関数を使用していません。だから、なぜ私は最初の場所で基底クラスの関数を使用することはありません派生クラスでオーバーライドする必要がある定義するだろうか?

私は本当に答えに感謝しています。この周辺の人々は非常に精通しているように見え、この場所は以前より多くの解決策を私に提供してくれました。今私は最終的に答えて投票する口座を持っています。

EDIT:

は、さらに、説明するために、私はまた、実際のprintertypeのオブジェクトにアクセスできるようにしたいと思います。たとえば、SerialTypeオブジェクトであるPrinterType1のPort変数。私はそれにアクセスしたいと思います: PrinterList[0].Port.Open()

そして下位ポートの全機能にアクセスできます。私は別のオブジェクトの(しかし異なる実装と)同じように動作する汎用関数を呼び出すしたいと思います。同時に:

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

私は、この特定のケースで使用するソリューションがあれば、OOPの基本についての良い本を選ぶことをお勧めします。良い本でも例が得られます。あなたが選ぶ言語の各機能を使用するには、WHENとHOWを参照してください。 –

+0

+1。優れたコード標準を開発したい。 –

答えて

9

インターフェイスを使用した疑似例。

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

非常に良い、早い提案をありがとう。 PrinterType2で定義されたIP変数が、編集したいSerialPort Portオブジェクトだったとします。直接アクセスできますか? Port.Dispose()、Port.Name()、Port.Open()など –

+0

インターフェイスは宣言するメソッド/プロパティのみを公開します。 IPrinterオブジェクトのコレクションがある場合、特定のインスタンスが実際にPrinterType2のインスタンスであるかどうかを判断し、適切にキャストする必要があります。これは、** is **と** as **演算子を使用して行うことができます。 – ThatBlairGuy

+0

したがって、1つのクラスにPortオブジェクトがあり、1つのクラスに2つのオブジェクトが含まれていればリストを入力します。 PrinterType2のいずれか。そのうちの1つだけに "ポート"オブジェクトがあります。どうすればそれにアクセスできますか?私はおそらくここで何かを逃している可能性が高いですが、上記のコードでは、私は2つのクラスのいずれかに存在するオブジェクトにどのようにアクセスするのか分かりません。あなたはリストメンバーのタイプをチェックし、それが実際にあるタイプ(またはリストに追加したときのタイプ)にキャストし、そこからアクセスして実際の基本オブジェクトを編集する必要があると言っていますか? –

2

あなたの「共通」メソッドを保持しているインターフェース(たとえばIPrinterType)を作成し、代わりにこのインタフェースを使用してください。

+0

ありがとうございます。私はいくつかのインタフェースを調査しましたが、私が読んだところからは、このように変数を使うことはできません。ですから、すべての変数を代わりにプロパティにする必要があります。私はそれが好きではありません。それは一つの解決策です。 –

0

どのようなインターフェイスが設計されているかは、かなりの違いがあります。すべての共通プロパティ/メソッドをその中に置き、具体的な実装を隠す。明らかに、共有可能な同様のコードが存在するので、ベースのPrinterクラスを持つことをお勧めします。

もっと定義されたプロパティについては、たとえばPort/IPでは、あなたが扱っているタイプを知る必要があります。その時点で正しいタイプにキャストできます。

+0

はい、それは私がどこかでフィッティングするのが最も難しいより定義されたプロパティです。私は派生クラスの1つにしか存在しないオブジェクト(例えばSerialPort)にアクセスしたいと思います。 Listはその型で定義されているので、基本クラスからアクセスしたいと思います。 –

+0

@jeah_wicerだから、その特定の派生型にキャストする必要があるシナリオです。 'var castedObj =これはDerivedTypeと同じです。 if(castedObj!= null){...} '。 – James

2

あなたが探していることはそうのように、抽象基底クラスです:

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

あなたは、そのクラスから継承し、必要に応じて、あなたのセンド()関数を実装します。

ここでもインターフェイスを使用できます。違いは、Interfaceは継承者が実装しなければならないプロパティ、メソッド、およびイベントのみを指定できることです。つまり、コード自体は実装されていません。どちらを使用するかは、アプリケーションに最適なものによって異なります。あなたは、両方を行うことを諦めるかもしれません(インターフェイスを実装する抽象クラスを作成する)。

1

「たとえば、文字列のSend(文字列メッセージ)」関数を基本クラス自体に使用していないという特定の質問については、なぜ派生クラスでオーバーライドする必要があるのか​​を定義します私はこれまでにベースクラスの関数を使用しませんでしたか?

基本クラスで実装する必要はありません。

基本クラスが抽象クラスの場合は、それを宣言してから具体的なクラスに任せて実装することができます。

具体的な実装を提供したくない場合は、抽象クラスの代わりに、すべての具体的なクラスが実装する必要があるインタフェースを使用する方がよいでしょう。