如何在C#中默认参数Guid.Empty?
我想说:
public void Problem(Guid optional = Guid.Empty) { }
但编译器抱怨Guid.Empty不是一个编译时间常量。
由于我不想更改API,我不能使用:
Nullable<Guid>
解
你可以使用new Guid()
public void Problem(Guid optional = new Guid()) { // when called without parameters this will be true var guidIsEmpty = optional == Guid.Empty; }
您也可以使用default(Guid)
default(Guid)
也会像new Guid()
。
因为Guid是一个值types而不是引用types,所以default(Guid)
不等于null
,例如,相当于调用默认的构造函数。
这意味着这个:
public void Problem(Guid optional = default(Guid)) { // when called without parameters this will be true var guidIsEmpty = optional == Guid.Empty; }
这与原来的例子完全一样。
说明
为什么没有Guid.Empty
工作?
你得到错误的原因是因为Empty
被定义为:
public static readonly Guid Empty;
所以,它是一个variables,而不是一个常量(定义为static readonly
而不是const
)。 编译器只能将编译器已知的值作为方法参数的默认值(而不是运行时已知的)。
根本原因是你不能有任何struct
的const
,不像enum
例如。 如果你尝试,它不会编译。
原因再一次是, struct
不是一个原始types。
有关.NET中所有基元types的列表,请参阅http://msdn.microsoft.com/zh-CN/library/system.typecode.aspx
(注意enum
通常inheritanceint
,这是一个原语)
但new Guid()
也不是一个常量!
我并不是说它需要一个常数。 它需要一些可以在编译时决定的东西。 Empty
是一个字段,所以它的值在编译时间是不知道的(只在运行时开始)。
在编译时必须知道缺省的参数值,这可能是一个常量值,或者是使用C#特性来定义的,这个特性可以在编译时使值成为已知的,比如default(Guid)
或者new Guid()
因为你不能修改代码中的struct
构造函数)。
虽然您可以轻松地提供default
或new
,但不能提供const
(因为它不是原始types或enum
,如上所述)。 所以,不要说可选参数本身需要一个常量,但是编译器已知的值。
Guid.Empty
相当于new Guid()
,相当于default(Guid)
。 所以你可以使用:
public void Problem(Guid optional = default(Guid))
要么
public void Problem(Guid optional = new Guid())
请注意, new Foo()
值仅适用于以下情况:
- 你真的调用了无参数的构造函数
-
Foo
是一个值types
换句话说,当编译器知道它实际上只是types的默认值:)
(有趣的是,我99.9%确定它不会调用你可能创build的任何自定义的new Foo()
构造函数,你不能在C#中创build这样的构造函数,但是你可以在IL中创build。
您可以使用任何types的default(Foo)
选项。
你不能使用:
default ( Guid )
?
接受的答案在ASP.NET MVC中不起作用,并导致此运行时错误:
[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....
相反,您可以执行以下操作:
public void Problem(Guid? optional) { if (optional == null) { optional = new Guid(); } }
编译器是非常正确的; Guid.Empty
不是编译时常量。 你可以尝试使一个方法超载如下:
public void Problem() { Problem(Guid.Empty); }