9

答えはノーだと思いますが、次のようなことが可能かどうか知りたいです:

public class MyGenericClass<TSomeClass> {
    public void MyGenericMethod<TSomeInterface>() 
        // This doesn't compile.
        where TSomeClass : TSomeInterface 
    {
        //...
    }
}

TSomeInterface上記の (動作しない) 例で示していることは、任意の基本クラス、実装されたインターフェイス、または (本当に凝りたい場合) の暗黙的な変換になるように制約することですMyGenericClass

注: これが C# で実装されなかった理由は、一般的な制約が実際にはコード コントラクトを意図したものではないためだと思われます。これが、ここで使用しようとしている方法です。TSomeInterfaceによって実装されている限り、タイプが何であるかは本当に気にしませんTSomeClass

これまでのところ、私はこれを一緒にハッキングしました:

public class MyGenericClass<TSomeClass> {
    public void MyGenericMethod<TIntermediateType, TSomeInterface>() 
        where TIntermediateType : TSomeClass, TSomeInterface 
    {
        //...
    }
}

これは、多かれ少なかれ、私が望む制約を強制します (それTSomeClassは、から継承する必要があるか、インターフェイスの場合は、実装する必要がありTSomeInterfaceますTIntermediateType) 。 TSomeClass):

var myGenericInstance = new MyGenericClass<TSomeClass>();
myGenericInstance.MyGenericMethod(TSomeClass, TSomeInterface);

さらに、上記のハックは、呼び出し元が理論上TSomeClass、最初の型パラメーターとして のサブクラスを指定でき、サブクラスのみが を実装する可能性があるため、壊れていますTSomeInterface

私がこれをしたい理由は、WCF サービスの流暢なファクトリ パターンを作成していて、(コンパイル時に) 呼び出し元がサービス クラスが作成しないコントラクトでエンドポイントを作成しようとするのを防ぎたいからです実装しないでください。私は明らかに実行時にこれをチェックできます (実際には WCF がこれを行ってくれます) が、私はコンパイル時のチェックの大ファンです。

私がここにいるものを達成するためのより良い/よりエレガントな方法はありますか?

4

3 に答える 3

3

これがコンパイルされない理由を理解する方法は次のとおりです。

このプログラムがコンパイルされると考えてください:

class Program {
    class Class1 { }
    class Class2 { }
    public class MyGenericClass<TSomeClass> {
        public void MyGenericMethod<TSomeInterface>() where TSomeClass : TSomeInterface {
        }
    }
    static void Main(string[] args) {
        var inst = new MyGenericClass<Class1>();
    }
}

すべてが良いです。コンパイラは満足しています。Mainここで、メソッドを変更することを検討してください。

static void Main(string[] args) {
    var inst = new MyGenericClass<Class1>();
    inst.MyGenericMethod<Class2>();
}

コンパイラは、Class1が実装されていないと文句を言いますClass2。しかし、どの行が間違っていますか? 制約は の呼び出しにありますMyGenericMethodが、問題のあるコード行は の作成ですMyGenericClass

言い換えれば、どちらが赤い波線を取得しますか?

于 2012-06-29T04:43:17.327 に答える
2

拡張メソッドは最善の解決策を提供しますが、すべての問題が完全に解決されるわけではありません。

public class MyGenericClass<TSomeClass>
{
}

public static class MyGenericClassExtensions
{
    public static void MyGenericMethod<TSomeClass, TSomeInterface>(this MyGenericClass<TSomeClass> self)
        where TSomeClass : TSomeInterface
    {
        //...
    }
}

を呼び出すときに両方の型を指定する必要がありますが、思いついたアプローチで可能なMyGenericMethodように、呼び出し元が間違った型を指定するのを防ぎます。TSomeClassこのアプローチでは、メソッドを次のように呼び出すことができます。

var myGenericInstance = new MyGenericClass<TSomeClass>();
myGenericInstance.MyGenericMethod<TSomeClass, TSomeInterface>();

MyGenericClassで宣言された型パラメータが最初の型パラメータと一致しない場合、コンパイル エラーになりますMyGenericMethod

最初の型パラメーターはthis引数によって推論できるため、メソッドへの追加パラメーターの場合、コンパイラーは両方の型パラメーターを推論できることがよくあります。

于 2015-06-25T11:57:37.000 に答える