2012-01-27 1 views
4

次のコードは、私が何をしたいのかを示しています。つまり、anObjectを制約し、IInterfaceOneまたはIInterfaceTwoを使用してさまざまなメソッドのパラメータとして使用できるようにしたいと思います。メンバーをジェネリックスなしで2つのインターフェースを実装するものとして定義/制約できますか?

public interface IInterfaceOne { } 
public interface IInterfaceTwo { } 

public class Implementation : IInterfaceOne, IInterfaceTwo 
{ 
} 

public interface IInterfaceOneAndTwo : IInterfaceOne, IInterfaceTwo { } 

public class UsingImplementation 
{ 
    IInterfaceOneAndTwo anObject = (IInterfaceOneAndTwo)(new Implementation()); //fails because Implementation doesnt acctually implement IInterfaceOneAndTwo 
} 

IInterfaceOneAndTwoは独自の権利でインタフェースであり、実装がそれを実装していないので、この例では、しかし、失敗します。

私がジェネリック薬を使用するのであれば、私はそれらを拘束することができますが、ジェネリック医薬品なしでこれを行う方法があれば疑問に思いますか?

anObjectIInterfaceOneAndTwoを使用せずにIInterfaceOneIInterfaceTwoを、実施しなければならないと言うする方法はありますか?

+2

悲しいことにC#はこれをサポートしていません。なぜなら、C#インターフェイスの動作にうまく適合しないからです。 – CodesInChaos

答えて

1

を持つことができますが、ない施設がためにありません変数またはフィールドを使用して "複合"型を表します。さらに、複数の制約を結合するジェネリック型のパラメータにオブジェクトを渡すには、そのオブジェクトを実際にそれらの制約のすべてを実装する型にキャストする必要があります。これは難しいことがあります。

たとえば、クラスFooBarの両方がIntf1Intf2を実装しているとします。ある人は、関数AddToList<T>(thing as T) where T:Intf1,Intf2を書こうと思っています。このような関数は、FooまたはBarのオブジェクトを完全に喜んで受け入れます。しかし、そのような関数を使用して、同じリスト(すべてFoo,Barなど)に加え、Intf1Intf2を実装している他のタイプの数の組み合わせでも構いませんが、後でそれらを渡すとしますオブジェクトは、同様に、Intf1Intf2の両方を実装するようにパラメータが制約されている関数に渡します。一つはFooFooであることが起こった、とBarBarであることを起こった任意のオブジェクトにキャスト任意のオブジェクトにキャストできますが、他のタイプもIntf1Intf2を扱うどの書かれている場合、それらに対処することは困難であろう。

Reflectionなどのトリックを使用せずに、やや面倒に問題を解決することは可能です。メソッドActUpon<thingType>ActUpon(thingType thing) where thingType: Base1, Base2を持つインタフェースIActUpon<Base1, Base2>を定義します。そのような方法の実装は、をBase1Base2に制約された汎用メソッドパラメータを必要とする他のメソッドに渡すことができる。そのようなアプローチの最大の難点は、可能な制約の数ごとに別々のコードを書く必要があり、ラムダ式を使用する多くの場所では代わりにIActUpon...の実装を書く必要があるということです。

+0

ありがとう、これは私が知る必要があることを教えてくれる - 私は '着信'と '静的な'フィールド/メンバーの区別の点からそれを見たことはありません。このように考えると、ジェネリックスがこれをどのようにサポートしているのか見ることができますが、 '匿名の'コンポジットはコンパイラからあまりにも多くを求めるかもしれません! – sebf

5

あなたが現在持っている方法ではありません。ジェネリック制約のみがその能力を持っています。

あなたはジェネリックを使用するように書き換えることができます:これが望ましい場合、組み合わせインタフェースを実装する必要がありIInterfaceOneとIInterfaceTwoと実装クラス間の論理接続が存在しなければならない

public class UsingImplementation<T> 
    where T : IInterface1, IInterface2, new() 
{ 
    T anObject = new T(); 

    void SomeMethod() { 
     anObject.MethodFromInterface1(); 
    } 
} 
1

を:

class Implementation : IInterfaceOneAndTwo { ... } 

これが可能でない場合は、コードが(すべて)コードではないため、UsingImplementationを再考する必要があります。それは単に利用可能な表面に適合しません。

2

あなたはまた、「着信」ジェネリッククラスのパラメータとジェネリックメソッドのパラメータは、タイプを組み合わせることができ、一般的な方法だけでなく、一般的なクラス

public void DoSomething<T>(T value) 
    where T : IInterface1, IInterface2 
{ 
    value.DoInterface1Things(); 
    value.DoInterface2Things(); 
} 

それとも

public void DoSomething<T>() 
    where T : IInterface1, IInterface2, new() 
{ 
    T anObject = new T(); 
} 
+0

トピックを読んだか? – CodesInChaos

+0

はい、私はしました。つまり、ジェネリッククラスを持つ必要はないので、ジェネリッククラスに比べてこのソリューションをより普遍的にすることができます。 –

+0

私が(おそらく過密に)私の答えに触れているこのアプローチの難しさは、ではないフィールドを持つ制約を持つルーチンを呼び出すことは非常に難しいということです。は、フィールドは実際にそれらを満たすオブジェクトを保持します)。これは変数に特有の問題ではありませんが、コレクション内の項目が単一の共通基盤を共有しない場合、そのような型のコレクションを永続化することを非常に困難にする可能性があります。 – supercat

2

あなたはジェネリックせずにC#でそれを行うことはできませんが、ここでは言及されなかった、あなたのために合うかもしれないジェネリックせずに問題を解決代替回避策があります。このスタイルは、IoCの原則と一緒に使用されることがよくあります。 同じオブジェクトを2度注入することができます。私はあなたのサンプルを変更してみましょうかなり...

public interface IInterfaceOne { void Hello(); } 
public interface IInterfaceTwo { void World(); } 

public class Implementation : IInterfaceOne, IInterfaceTwo 
{ 
    public void Hello() { }; 
    public void World() { }; 
} 

public class UsingImplementation 
{ 
    private readonly IInterfaceOne one; 
    private readonly IInterfaceTwo two; 

    public UsingImplentation(IInterfaceOne one, IInterfaceTwo two) 
    { 
     this.one = one; 
     this.two = two; 
    } 

    // do the stuff you want to do with an IInterfaceOne using field one 
    public DoSomeThingWithOne() { one.Hello(); } 

    // do the stuff you want to do with an IInterfaceTwo using field two 
    public DoSomeThingWithTwo() { two.World(); } 
} 

に次に、あなたが物事をこのようにアップ配線できます

var oneAndTwo = new Implementation(); 

var a = new UsingImplementation(oneAndTwo, oneAndTwo); 

// operates on the first param (which is the same as the second) 
a.DoSomeThingWithOne(); 

// operates on the second param (which is the same as the first) 
a.DoSomeThingWithTwo(); 

はIoCの原則のために見て(制御の反転)と依存性の注入を持って、このようなソリューションを見つけることができます。

このように、InterfaceOneとInterfaceTwoの2つを組み合わせた余分なインターフェースを作成する必要はありません。

+0

+1ありがとうございます。私が見てきたこのパターンは、このタイプの問題に対する受け入れられた解決策であるように見え、暗黙の変換演算子は意図された方法で使用できるものに可能な限り近いものです。 – sebf

関連する問題