如何在C#中将参数默认为Guid.Empty?

如何在C#中将参数默认为Guid.Empty?,c#,c#-4.0,optional-parameters,C#,C# 4.0,Optional Parameters,我想说: public void Problem(Guid optional = Guid.Empty) { } 但是编译器抱怨Guid.Empty不是编译时常量 由于我不想更改API,因此无法使用: Nullable<Guid> Nullable 您不能使用: 默认(Guid)?编译器非常正确Guid.Empty不是编译时常量。您可以尝试使方法重载如下: public void Problem() { Problem(Guid.Empty); } Guid.Empt

我想说:

public void Problem(Guid optional = Guid.Empty)
{
}
但是编译器抱怨Guid.Empty不是编译时常量

由于我不想更改API,因此无法使用:

 Nullable<Guid>
Nullable
您不能使用:


默认(Guid)

编译器非常正确<代码>Guid.Empty不是编译时常量。您可以尝试使方法重载如下:

public void Problem()
{
    Problem(Guid.Empty);
}

Guid.Empty
相当于
newguid()
,它相当于
default(Guid)
。因此,您可以使用:

public void Problem(Guid optional = default(Guid))

请注意,
new Foo()
值仅在以下情况下适用:

  • 你真的在调用无参数构造函数吗
  • Foo
    是一种值类型
换句话说,当编译器知道它实际上只是类型的默认值时:)

(有趣的是,我99.9%确定它不会调用您可能创建的任何自定义
new Foo()
构造函数。您不能在C#中的值类型中创建这样的构造函数,但可以在IL中创建。)

您可以对任何类型使用
default(Foo)
选项。

解决方案 您可以改用
newguid()
您还可以使用
默认(Guid)
default(Guid)
也将与
newguid()完全相同

因为Guid是值类型而不是引用类型,所以,
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;
因此,它是一个变量,而不是常量(定义为
静态只读
而不是
常量
)。编译器只能将编译器已知值作为方法参数的默认值(不包括仅已知的运行时)

根本原因是您不能拥有任何
结构的
const
,例如与
enum
不同。如果您尝试它,它将无法编译

原因再次是
struct
不是基元类型。
有关.NET中所有基元类型的列表,请参见
(请注意,
enum
通常继承
int
,这是一个原语)

但是
newguid()
也不是常数! 我不是说它需要一个常数。它需要一些可以在编译时决定的东西
Empty
是一个字段,所以它的值在编译时是未知的(仅在运行时的最开始)

默认参数值必须在编译时已知,可以是
const
值,也可以是使用C#特性定义的在编译时已知值的值,如
Default(Guid)
new Guid()
(这是在编译时为
struct
s决定的,因为您不能在代码中修改
struct
构造函数)


虽然可以轻松地提供
默认值
新建
,但不能提供
常量
(因为它不是上文解释的基本类型或
枚举
)。因此,再次强调,不是说可选参数本身需要常量,而是编译器已知值。

接受的答案在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();
    }
}

我说过我不想改变API,我试图驯服的方法已经超过了10个参数!@Ian Ringrose,尽管我同意
Guid x=default(Guid)
作为解决方案,请记住,添加另一个函数重载并不比添加可选参数更使API复杂。可选参数就是这样做的。@tenfour,必须有许多新函数重载才能与10个可选参数相同!如果您有一个需要10个以上参数的公共函数呃,也许让一个参数可选并不是一个真正的解决办法……而且,回顾最初的问题,你确实说你不想“更改API”(就像tenfour指出的,显式重载和可选参数之间的区别在实践中是最小的)但问题中没有提到参数列表是那种怪物。事实上,这是问题的完美答案。为什么编译器错误消息没有告诉我这一点,编译器可以检查Guid.Empty的大小写,并给出一个更有用的消息。@Ian Ringrose:我认为编译器不应该有speci类型FIC消息一般来说,老实说。设置一个参数默认为一个新对象,每次在PHP中调用该方法时,都会创建一个新对象,但只在Python中为整个程序创建一个对象。通过简单地禁止默认参数中的新对象来避免这个问题…尽管在PHP中这种功能有时非常好。为什么在ASP.NET MVC控制器操作中同样的功能不起作用?所有其他可选参数都起作用(int,string),但它对GUID不起作用,他说“/”应用程序中出现服务器错误。参数字典包含不可为null的类型为“System.Guid”的参数“categoryId”的null条目。代码在两种规范(默认(Guid)和新Guid()下都可以正常编译)但是出现了这个错误。@mare:恐怕我不知道。另一个选项可能是使用
null
。好吧,它不需要普通的常量表达式-
new Guid()
不是常量表达式。例如,C规范非常清楚地定义了允许的内容,包括但不限于常量。(需要明确的是,它实际上是一个编译时常量,而不是C#spec术语中的“常量表达式”)。请阅读我回复中的部分说明。添加到回答此部分。很好的解释。谢谢!您现在只能使用
default
:)Wha的可能副本
[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();
    }
}