2011-06-27 16 views
2

実行時に指定された型に基づいて汎用型のアクションを作成できますか?この特定のシナリオでは、アクションの本体は最終的に引数タイプを無視します。型付きアクション<>は、引数のないアクションを囲むラッパーにすぎません。実行時に汎用型のアクション<>を作成する

Action original =() => { }; 
... 
Action<TType> wrapper = (arg) => { 
    original(); 
} 

か、さえ:

Action<TTypeA, TTypeB> wrapper = (arg) => { 
    original(); 
} 

あなたが見ることができるように、入力されたアクション<>のボディは、それが単なるラッパーとして動作しています、引数、およびそのタイプを無視します。

なぜこのラッパーを最初に作成したいのか不思議であれば、「基本的な」バージョンは、Delegate.Combine()を実行するためにアクションをデリゲートに最終的に変換していることですタイプ。私がDelegate.Combine()で達成しようとしているのは、デリゲートが解雇されたという基本的な通知です。

この時点で、私はおそらく、これらのタイプの嫌悪感を避けるために私のデザインを再加工しますが、これがどのように達成されるのかはまだ非常に不思議です。

私が得ることができる最も近い従っていました:

private static TType GetTypedDelegate<TType>(Action onComplete) 
     where TType : class 
    { 
     MethodInfo info = typeof(TType).GetMethod("Invoke"); 
     ParameterInfo[] parameters = info.GetParameters(); 

     object result; 
     if (parameters.Length == 0) 
      result = onComplete; 
     else if (parameters.Length == 1) 
      result = GetTypedDelegate<TType>(onComplete, parameters[0].ParameterType); 
     // etc 

     TType onCompleteCasted = Delegate.CreateDelegate(typeof(TType), result, "Invoke") as TType; 
     return onCompleteCasted; 
    } 

    private static Delegate GetTypedDelegate<TType>(Action onComplete, Type type) 
    { 
     // This line isn't useful for me right now, since I can't just create a new 
     // instance of the action with a parameterless constructor ... but I thought I'd throw it in here in case it was of use 
     Type actionType = typeof(Action<>).MakeGenericType(new[] { type }); 

     // Do some magic here with the type information 
     // The following of course does not work,but you get the idea of what I am aiming for 

     Action<type> wrapper = (arg1) => 
     { 
      onComplete(); 
     }; 

     return wrapper as Delegate; 
    } 

答えて

1

私は最も簡単なオプションは、一般的な方法を記述して、(リフレクションを使用するか、または可能性もC#4 dynamicを使用して)それを動的に呼び出すことがあると思う:

class Helper { 
    public static Action<TType> Wrap1<TType>(Action arg) { 
    return (arg) => { original(); } 
    } 
} 

リフレクションを使用してメソッドを呼び出すと、ジェネリック型引数としてtyp1を使用すると、次のようになります。

+0

これはちょっとしたトリックです!今すぐ試してみてください。そのようなリターンの間に暗黙的な変換が起こることは私には起こりませんでした – Matt

1

リフレクションを使用したくない場合は、このようなクラスをいくつか設定できます。

public class ActionWrapper<TTypeA> 
{ 
    protected readonly Action _original; 
    public ActionWrapper(Action original) 
    { 
     _original = original; 
    } 
    public Action<TTypeA> Wrapped { get { return WrappedAction; } } 

    private void WrappedAction(TTypeA a) 
    { 
     _original(); 
    } 
} 

public class ActionWrapper<TTypeA,TTypeB>:ActionWrapper<TTypeA> 
{ 
    public ActionWrapper(Action original) : base(original) 
    { 
    } 

    public new Action<TTypeA, TTypeB> Wrapped { get { return WrappedAction; } } 

    private void WrappedAction(TTypeA a,TTypeB b) 
    { 
     _original(); 
    } 
} 
関連する問題