2015-09-09 10 views
11

私は現在、C#の問題に直面しています。実在のタイプを使用して解決できると思います。しかし、私はC#で作成できるのか、(他のいくつかの構造を使って)シミュレートされているのかどうかは分かりません。が、それが持っているどのような種類のパラメータ気にせずC#の存在タイプ?

public interface MyInterface<T> 
{ 
    T GetSomething(); 
    void DoSomething(T something); 
} 

public class MyIntClass : MyInterface<int> 
{ 
    int GetSomething() 
    { 
     return 42; 
    } 

    void DoSomething(int something) 
    { 
     Console.Write(something); 
    } 
} 

public class MyStringClass : MyInterface<string> 
{ 
    string GetSomething() 
    { 
     return "Something"; 
    } 

    void DoSomething(string something) 
    { 
     SomeStaticClass.DoSomethingWithString(something); 
    } 
} 

次の私は、このインターフェイスを実装するオブジェクトのリストを反復することができるようにしたい:

は基本的に私はこのようないくつかのコードを持っていると思います。このような何か:

public static void DoALotOfThingsTwice(){ 
    var listOfThings = new List<MyInterface<T>>(){ 
     new MyIntClass(), 
     new MyStringClass(); 
    }; 

    foreach (MyInterface<T> thingDoer in listOfThings){ 
     T something = thingDoer.GetSomething(); 
     thingDoer.DoSomething(something); 
     thingDoer.DoSomething(something); 
    } 
} 

MyIntClassで使用TMyStringClassで使用されるものが異なるので、これはコンパイルされません。

私はこのような何かがトリックを行うことができると考えていたが、C#でそうする有効な方法があるかどうかはわからない:

public static void DoALotOfThingsTwice(){ 
    var listOfThings = new List<∃T.MyInterface<T>>(){ 
     new MyIntClass(), 
     new MyStringClass(); 
    }; 

    foreach (∃T.MyInterface<T> thingDoer in listOfThings){ 
     T something = thingDoer.GetSomething(); 
     thingDoer.DoSomething(something); 
     thingDoer.DoSomething(something); 
    } 
} 
+2

タイプが不変であるため、いや、それができないのです。 – Servy

+2

'Action'で操作をラップし、それらをリストに格納することができます。これらのアクションは一般的に作成できます。 – Lee

答えて

5

DoALotOfThingsTwiceTには依存しませんので、Actionにラップして、代わりにリストに保存してください。

public static Action DoSomethingTwice<T>(this MyInterface<T> i) 
{ 
    return() => 
    { 
     T something = i.GetSomething(); 
     i.DoSomething(something); 
     i.DoSomething(something); 
    }; 
} 

その後、

var listOfThings = new List<Action>() { 
    new MyIntClass().DoSomethingTwice(), 
    new MyStringClass().DoSomethingTwice() 
}; 
+0

これは、私がそのリストでいくつかの追加作業を行うことができる場合にのみ有効です。例えば ​​'DoSomethingTwice'が値を返して' Func '(いくつかの' X'型のもの)を返すと、それらの 'X'値を使って(各関数を評価した後に)リスト上で操作することができます。しかし、私がDoSomethingTwice以外の何かをしなければ、DoSomethingTwiceを各オブジェクトで別々に呼び出すだけで、リストを一切使わなくてもいいでしょうか? – gonzaw

+0

@gonzaw - 最初に必要なリストを構築できないので、 'foreach'ループで各要素で' DoSomethingTwice'を別々に呼び出すことはできません。あなたは 'T'で抽象化できるところに何らかのラッパーを構築する必要があります。あなたの 'foreach'ループの中で' T 'の値を返す必要があるなら、同じ問題があります。つまり、C#はあなたが望むように実在型をサポートしていないので 'T'を全く記述できません。しかし、ループ内の各 'T 'で何をしますか?あなたは 'T 'を知らずに意味のあることをすることはできません。 – Lee

3

ない可能性を直接C#で。

あなたは型の安全性をドロップし、非ジェネリックベースのインタフェースを持っており、「汎用」のコードのためにそれを使用することができ、次のいずれか

public interface MyInterface 
{ 
    object GetSomething(); 
    void DoSomething(object something); 
} 

public interface MyInterface<T> : MyInterface 
{ 
    T GetSomething(); 
    void DoSomething(T something); 
} 

またはdynamicを使用する(再びなしコンパイル時の型の安全性):

foreach (dynamic thingDoer in listOfThings) 
{ 
    dynamic something = thingDoer.GetSomething(); 
    thingDoer.DoSomething(something); 
    thingDoer.DoSomething(something); 
} 

ハンドラの複数のバージョンを生成し、タイプ(How do I use reflection to call a generic method?)に基づいて(キャッシュ付きで)作成する(注:List<object>またはList<NonGenericBaseInterface>またはよりも「任意のオブジェクトのリスト」を実際に表現することはできません):

同様に、表現ツリーを使用して同様のコードを作成することもできます。

+0

これらのアプローチのどれをLINQと統合することができますか?たとえば、「public static void DoSomethingTwice (MyInterface thingDoer)」という関数に「generic」コードを抽出すると、あなたのアプローチの1つが 'listOfthings.Select(DoSomethingTwice)'を使ってマップできるようになりますか? 'object'を使ったアプローチのように思えるでしょうか? – gonzaw

+0

@gonzawはい、非ジェネリックなインターフェイスは、いくつかの型の安全性( 'List ')とlinq 'listOfthings.Select(DoSomethingTwice)'を使用しますが、要素の型のディスパッチを行いません - 'DoSomethingTwice'はすべての型に対して機能するか、コード内の型にディスパッチします。 –

1

私は防弾ソリューションを提供することはできません、あなたの実際のドメインであなたの根本的な問題だかわからないので。 what's covariance and contravariance in generic parameters both on interfaces and delegatesを見て、このアプローチでコードをリファクタリングしてみる価値があります。今の

、私はこれが可能な解決策であることを信じる:

public static void DoALotOfThingsTwice() 
{ 
    var listOfThings = new List<object> 
    { 
     new MyIntClass(), new MyStringClass() 
    }; 

    MyInterface<int> a; 
    MyInterface<string> b; 

    // During each iteration, check if the thing is a concrete 
    // implementation of your interface MyInterface<T>... 
    foreach (object thingDoer in listOfThings) 
    {   
     // ...and call MyInterface<T>.DoSomething method depending on 
     // the success of the cast to MyInterface<int> or 
     // MyInterface<string> 
     if ((a = thingDoer as MyInterface<int>) != null) 
      a.DoSomething(38); 
     else if((b = thingDoer as MyInterface<string>) != null) 
      b.DoSomething("hello world"); 
    } 
} 
関連する問題