2012-06-10 2 views
6

私はC#のと初心者だと、このための任意の答えを見つけることができません:一部のインターフェイスパラメータを指定してアクションを委任ますが、このインタフェース(またはクラス)を拡張するオブジェクトと関数を使ってプッシュしよう正しいアクションを委任する方法<Interface>?

イム

// 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); 

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

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

答えて

7

あなたは共分散を期待していますが、Action<T>であり、反例はです。これは唯一のタイプパラメータです。

evtCheckAction<IFace>インスタンスが期待するより一般的なIFaceタイプよりも、引数としてより具体的なタイプ(IntEvent)を必要とするので、あなたはevtCheckからAction<IFace>にメソッドグループの変換を行うことはできません。このような変換が許可されている場合、代理人がIFaceを実装する引数で実行されたにもかかわらず、IntEventではない場合、どのようなことが起こりますか?

私はそこに欠陥があるように見えるので、あなたのデザインをもう一度見ておくべきだと思いますが、必要ならば引数のキャストを強制的に強制するラムダを作成し、 InvalidCastException:もっと

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

おそらく、あなたはevtCheckは、より具体的なデリゲートを受け入れるために、より一般的なタイプやsetActionを受け入れるようにしたいかもしれません。 Tは、あなたのIntEventクラスは、しかし、コンパイラはあなたのsetAction()を受け入れた場合という意味IFaceインタフェースを実装しU.

から派生している場合Action<T>を取る方法もAction<U>を受け入れるよう

4

Action<T>は、Tで反変です別のIFace-derivativeで、IntEventではない引数を使用してevtCheck()を呼び出すことは可能です。これはランタイムエラーであり、型の安全性の明確な違反です。

必須エリックリペット参照:Covariance and contravariance

EDIT:あなたの説明から、あなたが本当にしたいことはそう例えば、メソッドのパラメータの型に基づいた差別であると私には思えますIntEventの別のアクションが必要です。もう1つは(仮説)DoubleEventなどです。この場合は、実際にはC#で直接サポートされていないダブル仮想ディスパッチの後ですが、Visitorデザインパターンを使用してシミュレートできます。

+0

これは私がやろうとしていることです。アクション関数は、常に同じインタフェースまたはオブジェクトを拡張するオブジェクトを期待します。さて、訪問者のデザインパターンを見てみましょう。 – turbosqel