基本クラスから派生した 2 つの具象クラスがあります。具体的なクラス A には、具体的なクラス B と比較して 10 個の追加のプロパティがあります。次のように、パラメーターの1つが基本クラスのリストであるメソッドがありますList<baseClass>
。メソッド内では、リストをループし、適切な具象クラスにキャストして、プロパティにアクセスする必要があります。これを達成する方法を教えてください。これを行うための適切な設計パターンはありますか?
5 に答える
c# には、調べることができるGetTypeメソッドがあります。
is
オペレーターもいます
if (baseClass is derivedClass)
{
// do what you will with derived class.
}
しかし
一般的に、あなたがしていることは、そもそも悪いデザインパターンです。基本クラスを反復処理してから派生クラスにキャストすると、ポリモーフィズムのポイント全体が失われます。
必要な種類の操作を実行できるメソッドを基本クラスに作成できるかもしれません。
これが基本的なアプローチです。
foreach(baseClass x in theList)
{
if (x is classA)
{
classA a = (classA) x;
...
}
else if (x is classB)
{
classB b = (classA) x;
...
}
}
複数のタイプを分割する必要がある場合、それほど単純にはなりません。インターフェイスまたは別の継承モデルを使用して、すべてを回避しようとすることができます。詳細を見ないと正確なことは言えません。
ここでは、 C# の動的型が役に立つと思います。
class BaseClass {}
class ConcreteClass1 : BaseClass
{
void Display1 () {}
}
class ConcreteClass2 : BaseClass
{
void Display2 () {}
}
void Enumerate (List<BaseClass> baseItems)
{
foreach (BaseClass baseItem in baseItems)
{
ConcreteAccessor ((dynamic)baseItem);
}
}
void ConcreteAccessor (ConcreteClass1 concreteItem1)
{
concreteItem1.Display1 ();
}
void ConcreteAccessor (ConcreteClass2 concreteItem2)
{
concreteItem2.Display2 ();
}
ここで重要なのは、具象クラスごとに異なるオーバーロードを 1 つ持ち、動的を使用してシームレスな方法でそれらの 1 つを呼び出すことです。利点は、オーバーロードが実行時に解決され、コードがきれいに見えることです。
実行時の型解決であるため、コンパイル時の検証は実行されません。具象型の 1 つのオーバーロードが失われ、実行時にbaseItemがその特定の具象型に解決されるとします。次に、オーバーロードがないため、実行時エラー (クラッシュ) が発生します。
もう 1 つの落とし穴は、dynamicがボンネットの下で Reflection を使用することです。ご存じのとおり、リフレクションはアプリケーションの速度を低下させます。
foreach(var baseClass in baseClasses)
{
if(baseClass.GetType() == typeof(ClassA)
{
var myClassA = (ClassA) baseClass;
dowork();
}
else if(baseClass.GetType() == typeof(ClassB)
{
var myClassB = (ClassB) baseClass;
dowork();
}
}
明示的なキャストを避けるために、別の方法で進めることをお勧めします。基本クラスに、具象クラスのプロパティで動作する抽象メソッドを配置します。
例えば:
public abstract void DoSomethingUsingProperties();
具体的なクラスでは、適切なビジネス ロジックを使用して実装 (オーバーライド) します。
次に、パラメーターの1つが基本クラスのリストであるメソッドで、次のようなことができます:
public void YourMethod(List<BaseClass> list, ...other params)
{
// ...
foreach(var bc in list)
{
// so you don't need to know specific properties of concrete classes...
bc.DoSomethingUsingProperties();
}
//...
}