希望以下示例能够比标题更好地解释问题:/
假设我们有一个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)
相同的操作。
不幸的是,这是我的反射技能让我失望的地方。
答案 0 :(得分:0)
创建一个通用类来存储通用委托,而不是使用泛型方法。
您可以将泛型方法的调用委托给泛型类型中的方法。