如何将带可选参数的方法参数传递给另一个带可选参数的方法?
如何在C#中传递可选参数而不硬编码目标方法的默认值
方案1:使用方法重载(适合参数数量少的场景)
直接为G方法提供多个重载版本,对应是否传递可选参数的情况,完全复用F方法的默认值,无需额外判断:
public class FClass{ public void F(string input1, string input2 = "my default string"){ // Do stuff } } public class GClass{ private readonly FClass _fClass = new FClass(); // 无可选参数的重载:调用F的单参数版本,让F用自身默认值 public void G(string input1){ var someVar = input1; // 示例业务逻辑 _fClass.F(someVar); } // 带可选参数的重载:直接传递参数给F public void G(string input1, string input2){ var someVar = input1; // 示例业务逻辑 _fClass.F(someVar, input2); } }
优点:
- 代码直观,无冗余判断逻辑
- 完全遵循
FClass的默认值定义,不用在GClass重复维护 - 性能最优,无额外开销
缺点:
- 可选参数数量多的时候,需要创建
2^n个重载版本,代码冗余度高
方案2:利用[CallerArgumentExpression]检测参数是否被显式传入(C# 10+)
用C# 10引入的[CallerArgumentExpression]特性,直接判断用户是否显式传入了可选参数,不用额外类型包装:
public class FClass{ public void F(string input1, string input2 = "my default string"){ // Do stuff } } public class GClass{ private readonly FClass _fClass = new FClass(); public void G(string input1, string input2 = default, [CallerArgumentExpression(nameof(input2))] string input2Expr = null){ var someVar = input1; // 示例业务逻辑 // 只要input2被显式传入(哪怕值是null),input2Expr就不为空 if(input2Expr != null){ _fClass.F(someVar, input2); } else { _fClass.F(someVar); } } }
优点:
- 无需额外类型或重载,代码简洁
- 精准区分“未传入参数”和“传入参数值为默认值”的场景
- 完全复用
FClass的默认值定义
缺点:
- 仅支持C# 10及以上版本
- 多参数场景下要为每个可选参数添加对应的
[CallerArgumentExpression]参数
方案3:自定义Optional<T>类型(兼容所有C#版本)
自己封装一个可选类型,专门标记参数的“是否传入”状态,而非仅依赖参数值:
// 自定义可选类型 public struct Optional<T> { public bool HasValue { get; } public T Value { get; } private Optional(T value) { HasValue = true; Value = value; } // 允许隐式转换,调用时不用手动包装参数 public static implicit operator Optional<T>(T value) => new Optional<T>(value); // 定义空实例,代表未传入参数 public static readonly Optional<T> Empty = new Optional<T>(); } public class FClass{ public void F(string input1, string input2 = "my default string"){ // Do stuff } } public class GClass{ private readonly FClass _fClass = new FClass(); public void G(string input1, Optional<string> input2 = default){ var someVar = input1; // 示例业务逻辑 if(input2.HasValue){ _fClass.F(someVar, input2.Value); } else { _fClass.F(someVar); } } }
调用示例:
var g = new GClass(); g.G("test"); // 不传入input2,F用自身默认值 g.G("test", "custom value"); // 传入input2,直接传递给F
优点:
- 兼容所有C#版本
- 清晰区分参数是否被传入,不受默认值影响
- 多参数场景下只需替换参数类型,不用大量重载
缺点:
- 需要自定义类型(也可以用第三方NuGet包如
Optional)
方案4:使用反射(不推荐,仅作补充)
如果参数数量极多且无法用上述方案,可以通过反射动态构建调用,根据参数是否传入决定传递哪些值:
public class GClass{ private readonly FClass _fClass = new FClass(); private readonly MethodInfo _fMethod = typeof(FClass).GetMethod(nameof(FClass.F))!; public void G(string input1, string input2 = default){ var someVar = input1; // 示例业务逻辑 var parameters = new List<object> { someVar }; // 仅当input2被传入时添加参数(注意:如果F的默认值不是null,这个判断逻辑要调整) if(input2 != default){ parameters.Add(input2); } _fMethod.Invoke(_fClass, parameters.ToArray()); } }
优点:
- 参数数量变化时不用修改调用逻辑
缺点:
- 反射性能开销大,不适合高频调用场景
- 编译时无类型检查,容易出错
- 代码可读性差
内容的提问来源于stack exchange,提问作者Shark32
相关产品推荐
相关产品推荐

