如何传递参数数量可变的Func<T>委托
实现支持可变参数数量的
Func委托调用方案 要实现无需重载且调用语法简洁的GetValue方法,核心思路是利用自定义委托包装类+隐式类型转换,让不同参数数量的Func可以自动适配到同一个方法参数中,同时保留编译时的类型检查。
具体实现步骤
- 定义一个包装类
DynamicFunc,用于统一封装不同参数数量的委托,并提供统一的调用入口:
public class DynamicFunc { private readonly Delegate _underlyingFunc; public DynamicFunc(Delegate func) { _underlyingFunc = func ?? throw new ArgumentNullException(nameof(func)); } // 统一的调用方法,接收可变参数数组并转发给原委托 public object Invoke(params object[] args) { // 可添加参数数量匹配校验,避免运行时错误 var methodParams = _underlyingFunc.Method.GetParameters(); if (args.Length != methodParams.Length) { throw new ArgumentException($"Expected {methodParams.Length} parameters, got {args.Length}"); } return _underlyingFunc.DynamicInvoke(args); } // 为无参Func添加隐式转换 public static implicit operator DynamicFunc(Func<object> func) { return new DynamicFunc(func); } // 为单参数Func添加隐式转换 public static implicit operator DynamicFunc<TArg>(Func<TArg, object> func) { return new DynamicFunc(func); } // 为双参数Func添加隐式转换 public static implicit operator DynamicFunc<TArg1, TArg2>(Func<TArg1, TArg2, object> func) { return new DynamicFunc(func); } }
- 修改
GetValue方法,让它接收DynamicFunc参数,内部通过包装类的Invoke方法调用原委托:
public object GetValue(string name, DynamicFunc func) { // 替换成你实际获取参数的逻辑,比如从上下文/配置中根据name取参数 object[] parameters = GetParametersByName(name); return func.Invoke(parameters); } // 示例:模拟根据名称获取参数的逻辑 private object[] GetParametersByName(string name) { return name switch { "Bob" => Array.Empty<object>(), "Joe" => new object[] { 123 }, "Henry" => new object[] { 456, "test" }, _ => throw new ArgumentOutOfRangeException(nameof(name)) }; }
调用方式(完全符合你的需求)
// 无参数 var result1 = GetValue("Bob", () => "Bob Smith"); // 1个参数 var result2 = GetValue("Joe", (i) => $"Joe {i.ToString()}"); // 2个参数 var result3 = GetValue("Henry", (i, e) => $"i: {i.ToString()}, e: {e.ToString()}");
未来扩展
如果后续需要支持3个及以上参数的委托,只需要在DynamicFunc类中添加对应的隐式转换方法即可,不需要修改GetValue的方法签名:
// 支持三参数Func public static implicit operator DynamicFunc<TArg1, TArg2, TArg3>(Func<TArg1, TArg2, TArg3, object> func) { return new DynamicFunc(func); }
方案优势
- 调用者无需任何显式类型转换,语法简洁自然
- 无需重载
GetValue方法,核心逻辑集中在包装类中 - 保留了编译时的类型检查,避免纯
dynamic方案的运行时风险 - 扩展成本低,新增参数数量支持只需要添加对应转换方法
内容的提问来源于stack exchange,提问作者Sam Axe
相关产品推荐
相关产品推荐

