2011-06-27 49 views
2

是否有可能在運行時基於某些指定類型創建一個一般類型的Action?在這個特定的場景中,Action的主體最終會忽略參數類型,因爲類型化的Action只會是一個無參數Action的包裝,在運行時創建通用類型的Action <>

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

或者,甚至:

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

正如你所看到的,類型化的行動<>正文忽略的參數,和它們的類型,它只是作爲一個包裝。

如果您好奇我爲什麼要首先創建這個包裝器,那麼'基本'版本是我最終將Action轉換爲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作爲泛型類型參數看起來是這樣的:

var meth = typeof(Helper).GetMethod("Wrap1"); 
var gmeth = meth.MakeGenericMethod(new[] { typ1 }); 
var genericAction = gmeth.Invoke(null, new object[] { action }); 
+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(); 
    } 
} 
相關問題