简体   繁体   English

C# 委托类型作为通用约束

[英]C# Delegate Type As Generic Constraint

I have a function:我有一个功能:

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 is a class that contains several static methods. actionType是一个包含多个静态方法的类。 These methods are stored as strings in the CardData object.这些方法作为字符串存储在 CardData 对象中。 I provided an example using the OnTurnStarted callback.我提供了一个使用OnTurnStarted回调的示例。 It is very clunky to write out all that code repeatedly each time I want to add another callback.每次我想添加另一个回调时,重复写出所有代码是非常笨拙的。 I've tried creating a function:我试过创建一个函数:

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;
        }
}

However, where TDelegate : Delegate doesn't work.但是, where TDelegate : Delegate不起作用。 I can't just do some type checking in the method (ie:我不能只在方法中做一些类型检查(即:

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

because delagateToAddThisTo which is of type TDelegate and needs to be able to be added to.因为delagateToAddThisTo类型并且需要能够添加到。

Thank you in advance.先感谢您。

C# doesn't allow constraining generic type parameters with delegate types. C# 不允许使用委托类型约束泛型类型参数。 Your only option to validate delegate types is at runtime.验证委托类型的唯一选择是在运行时。

For the same reason, you won't be able to use the += operator inside the CreateCallback method.出于同样的原因,您将无法在CreateCallback方法中使用+=运算符。 But if += is moved to the caller ( SetupCallbacks ), and the CreateCallback only creates and returns the delegate, it can still look quite elegant:但是如果+=被移动到调用者( 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);

Where the CreateCallback method is as follows:其中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;
}

Provided that in my example, TurnManager class looks like this:假设在我的示例中,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 ...
}

Starting from C# 7.3 it is possible.从 C# 7.3 开始是可能的。

Example from Microsoft docs 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 { }

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM