2017-07-05 28 views
0

我有一個函數:C#的委託類型作爲通用的限制

private void SetupCallbacks() 
{ 
     Type actionType = Type.GetType(CardData.ActionFile); 
     if (actionType == null) 
      return; 

     // To get any particular method from actionType, I have to do the following 
     MethodInfo turnStarted = actionType.GetMethod(CardData.TurnStartedMethod); 
     if (turnStarted != null) 
     { 
      Delegate d = Delegate.CreateDelegate(typeof(Action<bool>), turnStarted); 
      Action<bool> turnStartedAction = (Action<bool>)d; 
      TurnManager.Instance.OnTurnStarted += turnStartedAction; 
     } 

     ... 
} 

actionType是一個包含了一些靜態方法的類。這些方法作爲字符串存儲在CardData對象中。我提供了一個使用OnTurnStarted回調的示例。每次我想添加另一個回調時,重複寫出所有代碼是非常笨拙的。我試過創建一個功能:

private void SetupCallback<TDelegate>(Type actionType, string method, TDelegate delagateToAddThisTo) where TDelegate : Delegate 
{ 
    MethodInfo methodInfo = actionsContainerClass.GetMethod(method); 
     if (methodInfo != null) 
     { 
      Delegate d = Delegate.CreateDelegate(typeof(Action<Card>), methodInfo); 
      TDelegate t = (TDelegate)d; 
      delagateToAddThisTo += t; 
     } 
} 

但是,where TDelegate : Delegate不起作用。我不能只是做一些類型檢查的方法(即:。

if(typeof(TDelegate).IsSubclassOf(typeof(Delegate)) == false) 
{ 
    throw new InvalidOperationException("Card::SetupCallback - " + typeof(TDelegate).Name + " is not a delegate"); 
} 

因爲delagateToAddThisTo它的類型是TDelegate和需要能夠被添加到

預先感謝您

+0

我想你會意識到,即使你讓它工作,'d elagateToAddThisTo + = t'將不起作用。對於事件'+ ='被轉換爲'add'方法,並且對於代表'delagateToAddThisTo'必須是變量(即'ref') –

回答

2

C#不允許與委託類型約束的泛型類型參數。你唯一的驗證委託類型的選擇是在運行時。

出於同樣的原因,你將無法使用+=運營商內部CreateCallback方法。但是,如果+=移動到主叫方(SetupCallbacks),以及CreateCallback只創建並返回委託,它仍然看起來很優雅:

// this code is in SetupCallbacks method 
// Action<...> delegates are just examples 

TurnManager.Instance.OnTurnStarted += 
    CreateCallback<Action<string, int>>(actionType, CardData.TurnStartedMethod); 

TurnManager.Instance.OnTurnStopped += 
    CreateCallback<Action<string, int, TimeSpan>>(actionType, CardData.TurnStoppedMethod); 

CreateCallback方法如下:

private TDelegate CreateCallback<TDelegate>(Type actionType, string method) 
    where TDelegate : class 
{ 
    if (!typeof(Delegate).IsAssignableFrom(typeof(TDelegate))) 
    { 
     throw new InvalidOperationException("Card::SetupCallback - " + typeof(TDelegate).Name + " is not a delegate"); 
    } 

    MethodInfo methodInfo = actionType.GetMethod(method); 

    if (methodInfo != null) 
    { 
     // the following line will also validate compatibility of delegate types 
     Delegate nonTypedDelegate = methodInfo.CreateDelegate(typeof(TDelegate)); 
     TDelegate typedDelegate = (TDelegate)(object)nonTypedDelegate; 
     return typedDelegate; 
    }    

    return null; 
} 

但在我的示例中,TurnManager類看起來像這樣:

public class TurnManager 
{ 
    public static TurnManager Instance 
    { 
     get { /* ....... */ } 
    } 

    public Action<string, int> OnTurnStarted { get; set; } 
    public Action<string, int, TimeSpan> OnTurnStopped { get; set; } 

    //... other members ... 
} 
+0

謝謝!完美工作。 –