2

私は100のクラスを持っており、それらにはいくつかの類似した要素といくつかの固有のものがあります。これらの類似したアイテムに名前を付けるインターフェイスを作成しました。例:interfaceIAnimal。私が通常することは次のとおりです。

class dog : IAnimal

しかし、100のクラスがあり、それらすべてを調べて、IAnimalを適用できるクラスを探す気にはなりません。

私がしたいのはこれです:

dog scruffy = new dog();
cat ruffles = new cat();

IAnimal[] animals = new IAnimal[] {scruffy as IAnimal, ruffles as IAnimal} // gives null

また

IAnimal[] animals = new IAnimal[] {(IAnimal)scruffy, (IAnimal)ruffles} //throws exception

その後、

foreach (IAnimal animal in animals)
{
   animal.eat();
}

クラスを書くときにIAnimalを書くことなく、c#でフリルとだらしないものをIAnimalとして扱うようにする方法はありますか?

ありがとう!

編集(怠惰ではありません):クラスはSQLストアドプロシージャメタデータから生成されます。つまり、生成されるたびに戻って追加するか、コードジェネレーターを変更してインターフェイスにあるメンバーを識別する必要があります。実際、それは悪い考えではありません。とはいえ、ある種のジェネリックアプローチか何かがあることを望んでいました。

4

11 に答える 11

10

あなたが求めているのはダックタイピングと呼ばれ、C#の一部ではありません。どんな解決策でも、振り返りとプロパティの確認が必要になります。手作業でクラスを確認する方が早いと思います。

でも試してみるのは面白いプロジェクトでしょう。

于 2009-01-22T17:35:04.403 に答える
6

この問題は部分クラスで解決できます。機械生成/再生成されたコードを各クラスの 1 つのソース ファイルに配置し、手動でコーディングした部分 (IAnimal からのサブクラスを定義) を別のソース ファイルに配置します。

于 2009-01-22T17:43:23.137 に答える
4

解決策は、コードジェネレーターを変更することです。現在、それはあなたのニーズには単純すぎます。関連するプロパティやメソッドがクラスに存在する場合は、インターフェイスの実装を追加する必要があります。

于 2009-01-22T17:34:16.480 に答える
4

eatリフレクションを介して" " にアクセスするアダプタを作成できます。

public class Adapter<T> : IAnimal
{
   private T x;

   Adapter(T x)
   {
     this.x = x;
   }

   public void eat()
   {
     x.GetType().GetMethod("eat").Invoke(this);
   }
}

次に、次のように使用できます。

dog scruffy = new dog();
cat ruffles = new cat();

IAnimal[] animals = new IAnimal[] {new Adapter<dog>(scruffy), new Adapter<cat>(ruffles )};
于 2009-01-22T17:57:16.277 に答える
1

正当な理由で猫のクラスを本当に変更できないと仮定すると、

IAnimalから継承した猫用のアダプターを書くことができます。

  class cat_adapter : IAnimal
  {
       private cat baseCat;
       public cat_adapter( cat aCat)
       {
           baseCat = aCat;
       }

       // Implement IAnimal interface and redirect to baseCat
       public void eat()
       {
            baseCat.munchOnMeowMix();
       }

  }

C ++では、生成されたすべてのクラスに次のような同じ関数が必要であると想定して、テンプレートを使用できます。

  template <class BaseType>
  class CAnimalAdapter : public IAnimal
  {
  private:
        BaseType* m_baseInstance;
  public:
        CAnimalAdapter(BaseType* baseInstance) :
            m_baseInstance(baseInstance)
        {
        }

        void eat()
        {
            // You will get a compiler error if BaseType doesn't have this implemented
            baseInstance->doEat();                
        }

  }

たぶん、私よりもC#-pyの方が、リフレクションで同じことができるでしょう。

于 2009-01-22T17:35:27.320 に答える
1

私が知っていることは簡単ではありませんが、リフレクションを使用して遅延バインディング呼び出しを行うことはできますが、クラスの編集またはマクロの作成に時間を費やしたほうがよいでしょう。

于 2009-01-22T17:35:32.827 に答える
1

コード ジェネレーターがクラスを部分として生成する場合、インターフェイスを実装する別の部分定義を追加できます。

于 2009-01-22T18:09:23.273 に答える
0

いいえ。具体的な基本クラスまたはインターフェイスがなくても、C#でこれを実行できるようにする方法はありません。

于 2009-01-22T17:34:19.723 に答える
0

メソッドをすでに実装していて、インターフェイスを実装したいだけの場合は、IDEでreplaceinfilesコマンドを使用して正規表現を使用できます。

それ以外の場合は、拡張メソッドを見てください。彼らはあなたのニーズに合うかもしれません。

于 2009-01-22T17:35:38.660 に答える
0

クラスはインターフェイス IAnimal を実装する必要があります。2 つの異なるクラスの同じ名前のメソッド/プロパティは、それらが両方ともインターフェイス/基本クラスの実装でない限り、同等とは見なされません。

于 2009-01-22T17:37:58.047 に答える
0

生成されたクラスを部分クラスとして実装する場合、これらのクラスにインターフェイスを実装し、コード ジェネレーターを変更して部分クラスの半分のみを生成することができます。これにより、インターフェイスの実装 (または追加することを決定したその他のカスタム ロジック) を失うことなく、クラスを再生成できます。

このタイプのアプローチは、LINQ to SQL がクラス ファイルを生成する方法です。

于 2009-01-22T17:46:15.207 に答える