我有一个功能:
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 :(得分:3)
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 ...
}
答案 1 :(得分:0)
从 C# 7.3 开始是可能的。
来自 Microsoft 文档的示例
public class UsingEnum<T> where T : System.Enum { }
public class UsingDelegate<T> where T : System.Delegate { }
public class Multicaster<T> where T : System.MulticastDelegate { }