在工厂中包装运行时生成的委托,并将调用结果作为参数传递

时间:2014-07-25 09:13:27

标签: c# reflection delegates

希望以下示例能够比标题更好地解释问题:/

假设我们有一个Calculator类,允许注册不同的函数:

public class Calculator
{
    public void RegisterFunction(string functionName, Func<int, int, int> function)
    {
        functions.Add(functionName, function);
    }

    public int Calculate(string functionName, int x, int y)
    {
        Func<int, int, int> function;

        if (functions.TryGetValue(functionName, out function))
        {
            return function(x, y);
        }

        throw new ArgumentException("No function is registered with name " + functionName);
    }
}

然后我们可以通过提供内联委托来注册“添加”功能:

calculator.RegisterFunction("add", (x, y) => x + y);
Console.WriteLine(calculator.Calculate("add", 2, 3));

但是,为了使我们的计算器更容易扩展并支持复杂的功能,我们提供了一个与内联委托具有相同签名的接口:

public interface ICalculatorFunction
{
    int Execute(int x, int y);
}

我们可以为Calculator创建一个扩展方法,以便轻松注册ICalculatorFunction个实例:

public static void RegisterFunction<TFunction>(this Calculator calculator, TFunction function) where TFunction : ICalculatorFunction
{
    calculator.RegisterFunction(typeof(TFunction).Name, function.Execute);
}

注册:

calculator.RegisterFunction(new Multiply());

但是,这里我们传递一个实例,实际上我们只想在需要执行计算时创建函数实例。我们可以通过传递“功能工厂”来支持这一点:

public static void RegisterFunction<TFunction>(this Calculator calculator, Func<TFunction> factory) where TFunction : ICalculatorFunction
{
    calculator.RegisterFunction(typeof(TFunction).Name, (x, y) => factory().Execute(x, y));
}

这里我们提供一个内联委托,它首先调用工厂,然后在创建的Execute实例上调用ICalculatorFunction

注册:

calculator.RegisterFunction(() => new Subtract());

问题

在编译时已知函数类型时,所有上述示例都可以正常工作。但是,我们需要支持传入计算器函数Type并在Register实例上调用相同的Calculator方法。

到目前为止,我只能提前创建ICalculatorFunction实例,使用Delegate.CreateDelegate然后将对Execute函数的引用传递给Calculator

public static void RegisterFunction(this Calculator calculator, Type functionType, Func<Type, object> factory)
{
    var delegateType = typeof(Func<,,>).MakeGenericType(typeof(int), typeof(int), typeof(int));
    var funcDelegate = (Func<int, int, int>)Delegate.CreateDelegate(delegateType, factory(functionType), "Execute");

    var registerMethod = calculator.GetType().GetMethod("RegisterFunction", BindingFlags.Instance | BindingFlags.Public);
    registerMethod.Invoke(calculator, new object[] { functionType.Name, funcDelegate });
}

注册:

calculator.RegisterFunction(typeof(Subtract), type => Activator.CreateInstance(type));

但是,funcDelegate我传递给Calculator.RegisterFunction需要有效地执行与我们的通用扩展(x, y) => factory().Execute(x, y)相同的操作。

不幸的是,这是我的反射技能让我失望的地方。

1 个答案:

答案 0 :(得分:0)

创建一个通用类来存储通用委托,而不是使用泛型方法。

您可以将泛型方法的调用委托给泛型类型中的方法。