6

私はC#の初心者ですが、これに対する答えは見つかりません:

いくつかのインターフェイスパラメータを使用してアクションを委任しようとしていますが、このインターフェイス(またはクラス)を拡張するオブジェクトを使用して関数をプッシュスルーします

// some class extending interface
public class IntEvent : IFace{}
public class MoveEvent : IFace{}

// function i like to use to verify Action
static void setAction(Action<IFace> evt) {
    // evt ...
}
// function to delegate as Action
static void evtCheck(IntEvent evt) {
    // some func
}
static void evtMove(MoveEvent evt) {
    // some func
}
// class {
//  call method inside class and delegate this function :
setAction(evtCheck);
setAction(evtMove);

インターフェイスを拡張しても、「にevtCheck(IntEvent)変換できません」というエラーが表示されます。Action<IFace>IntEventIFace

これをどのように解決すればよいですか?たぶん私はFuncまたはDelegateを使用する必要がありますか?

4

2 に答える 2

7

やろうとしていることを実行することはできません。共分散を期待していますが、その唯一の型パラメーターでAction<T>反変です。

インスタンスが期待するより一般的な型よりも引数としてより具体的な型( )が必要なため、からevtCheckへのメソッドグループ変換を行うことはできません。そのような変換が許可された場合、デリゲートが実装されているがそうではない引数を使用して実行された場合、どうなると思いますか?Action<IFace>evtCheckIntEventIFaceAction<IFace>IFaceIntEvent

そこに欠陥があるように見えるので、デザインをもう一度見直す必要があると思いますが、必要に応じて、ラムダを作成して引数のキャストを目的の型に強制し、InvalidCastException:の可能性を受け入れることができます。

setAction(iFace => evtCheck((IntEvent)iface));

よりevtCheck一般的なタイプsetActionを受け入れるようにするか、より具体的なデリゲートを受け入れるようにすることができます。

于 2012-06-10T16:09:29.567 に答える
5

Action<T>はTで反変であるため、をとるメソッドは、TがUから派生する場合Action<T>も受け入れます。Action<U>

ただしIntEvent、クラスはIFaceインターフェイスを実装します。つまり、コンパイラが呼び出しを受け入れた場合、実行時エラーと型安全性の明らかな違反ではなく、別の導関数である引数を使用しsetAction()て呼び出すことができます。evtCheck()IFaceIntEvent

必須のEricLippertリファレンス:共変性と反変性

編集:あなたの説明から、あなたが本当に望んでいるのはメソッドパラメータのタイプに基づく区別であるように思われます。たとえば、別のアクション、IntEvent(架空の)アクションDoubleEventなどが必要です。この場合、実際にはC#では直接サポートされていない二重仮想ディスパッチ後ですが、Visitorデザインパターンを使用してシミュレートできます。

于 2012-06-10T16:11:07.273 に答える