我正在编写一种方法(让我们称之为' Bar'),它接受许多参数。为方便起见,我设置了一个默认值,因此开发人员不必指定一堆“空”'在调用我的方法时。换句话说,我的方法的签名如下所示:
public void Bar(string paramA = null, string paramB = null, ... many more parameters omitted...)
我的方法中的代码检查空值并在这种情况下忽略参数。但是,在某些情况下,我需要区分默认情况' null值和开发人员故意设置的空值。
这是两个示例调用,用于说明我正在谈论的内容。第一个省略所有参数(因此C#编译器将在编译时用null替换它们)和开发人员决定指定的第二个样本' null'对于第一个参数。
Bar();
Bar(null);
我找到了几篇关于使用" Option / Some / None"图案。在我看来,最好的是here。
但我正在努力弄清楚我仍然可以提供一个'默认'开发商的价值'方便。从概念上讲,我想写这样的东西:
public void Bar(Option<string> paramA = Option.None)
但是C#编译器抱怨&#39; Option.None&#39;不是编译时常量。
答案 0 :(得分:2)
C#具有“重载”的概念,它是具有相同名称但具有不同参数的C#方法。
private void MethodA(string param1) {
}
private void MethodA(string param1, string param2) {
}
如果这不是您想要的,您还可以使用构建器模式。如果你担心这种事情,Builder
可能是一个减少内存分配的结构。
var result = new Builder()
.SetParam1(value)
.SetParam2(value)
.Build();
答案 1 :(得分:2)
不,没有办法区分它们。事实上,&#34;默认&#34;值被编译器烘焙到调用中,所以
Bar();
和
Bar(null);
导致等效的IL。
通常我会建议重载而不是默认值,但由于你有几个参数,重载次数会呈指数级增长。
如果您需要区分null
和&#34;默认&#34;那么你需要使用其他东西作为默认值。
另一种选择是创建一个可以存储所有参数值的类型。然后你可以判断一个&#34;参数&#34;是设置为null而默认为null,因为您可以挂钩到属性设置器。
答案 2 :(得分:1)
这基本上就是Nullable的用途。虽然它用于结构体,但您可以创建自己的包装类来执行相同的操作(使用强制转换操作符等)。
例如,您可以创建Argument&lt; T&gt;看起来像T一样,但有一个名为Set的属性返回一个bool。
然后你可以定义你的方法:
public void Bar(Argument<string> paramA = null, ...)
这是一个完整的例子,但我不得不承认我对它不满意。当作为参数传递时,我似乎无法获得隐式强制转换操作符。我曾经认为C#在几年前加入了这种强制,当时他们做了协变和逆变的演员。也许我错了。所以它仍然需要一个演员(我正在通过扩展方法)。
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Calling Foo(default(string).ToArg())...");
Foo(default(string).ToArg());
Console.WriteLine("Calling Foo(((string)null).ToArg())...");
Foo(((string)null).ToArg());
Console.WriteLine("Calling Foo(\"test\".ToArg())...");
Foo("test".ToArg());
Console.WriteLine("Calling Foo()...");
Foo();
Console.ReadLine();
}
public static void Foo(Argument<string> arg1 = null)
{
Console.WriteLine("arg1 is {0}null", arg1 == null ? "" : "not ");
Console.WriteLine("arg1.IsSet={0}", arg1?.IsSet ?? false);
Console.WriteLine("arg1.Value={0}", arg1?.Value ?? "(null)");
}
}
public class Argument<T>
{
public Argument()
{
IsSet = false;
}
public Argument(T t)
{
_t = t;
IsSet = true;
}
private T _t;
public T Value { get { return _t; } set { _t = value; IsSet = true; } }
public bool IsSet { get; private set; }
public static implicit operator T(Argument<T> t) { return t._t; }
}
public static class Extensions
{
public static Argument<string> ToArg(this string s) { return new Argument<string>(s); }
}
答案 3 :(得分:-2)
根据类型,您可以执行以下操作:
public static void Bar(string a = "", int b = 0) {
因为它们都没有价值,但仍然可以选择为空。 对于布尔值,我只是默认为false,因为布尔值是不可为空的。 这样:
public static void Bar(string a = "", int b = 0) {
if (a == "") {
// if there is no parameter
}
else {
// stuff
}
if (b == 0) {
// no param
}
else {
// stuff
}
希望我帮忙!