【问题标题】:How can I default a parameter to Guid.Empty in C#?如何在 C# 中将参数默认为 Guid.Empty?
【发布时间】:2011-07-04 07:54:15
【问题描述】:

我想说:

public void Problem(Guid optional = Guid.Empty)
{
}

但是编译器抱怨 Guid.Empty 不是编译时常量。

因为我不想更改我无法使用的 API:

 Nullable<Guid>

【问题讨论】:

标签: c# c#-4.0 optional-parameters


【解决方案1】:

解决方案

您可以改用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 是值类型而不是引用类型,所以,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;

所以,它是一个变量,而不是一个常量(定义为 static readonly 而不是 const)。编译器只能将编译器已知的值作为方法参数的默认值(不是运行时已知的)。

根本原因是您不能拥有任何structconst,这与enum 不同。如果你尝试它,它不会编译。

原因再次是struct 不是原始类型。
有关 .NET 中所有原始类型的列表,请参阅http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
(注意enum通常继承int,这是一个原语)

new Guid() 也不是常数!

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

必须在编译时知道默认参数值,它可以是 const 值,或者使用 C# 特性定义的值,在编译时知道值,例如 default(Guid)new Guid()(由在 structs 的编译时,因为您无法在代码中修改 struct 构造函数。

虽然您可以轻松提供defaultnew,但您不能提供const(因为它不是原始类型或enum,如上所述)。所以,再说一遍,并不是说可选参数本身需要一个常量,而是编译器已知的值。

【讨论】:

  • 嗯,它不需要一个普通的常量表达式——例如,new Guid() 不是一个常量表达式。 C# 规范非常清楚地定义了允许的内容,包括但不限于常量。 (为了清楚起见,它实际上一个编译时常量,而不是 C# 规范术语中的“常量表达式”)。
  • 阅读我回复中的解释部分。添加以回答这部分。
  • 很好的解释。谢谢!
  • 你现在只能使用default :)
【解决方案2】:

接受的答案在 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 不能更改为使用 Nullable - 足够公平
  • 除非你想明确地为参数“可选”分配一个空的 Guid 值,我认为这是定义 Guid 类型的可选参数的最自然的方法。
【解决方案3】:

你不能用吗:

default ( Guid )?

【讨论】:

  • 没有。 Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
  • 对不起,我不是这个意思??作为运营商,但作为一个强调的问号 - 我会编辑!
【解决方案4】:

Guid.Empty 等价于new Guid(),即等价于default(Guid)。所以你可以使用:

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

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

请注意,new Foo()适用于以下情况:

  • 您实际上是在调用 无参数 构造函数
  • Foo 是值类型

换句话说,当编译器知道它实际上只是类型的默认值时:)

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

您可以为 any 类型使用default(Foo) 选项。

【讨论】:

  • 现在为什么编译器错误消息没有告诉我这个,编译器可以检查 Guid.Empty 的情况并给出更有用的消息。
  • @Ian Ringrose:老实说,我认为编译器一般不应该有特定于类型的消息。
  • 将参数设置为默认为一个新对象,每次在 PHP 中调用该方法时都会创建一个新对象;但在 Python 中只为 整个程序 创建一个对象。真的,我认为这是very few design flaws of Python 之一。我很高兴 C#(和 VB.Net)通过简单地禁止默认参数中的新对象来避免这个问题......尽管有时这种能力在 PHP 中非常好。
  • 同样的事情在 ASP.NET MVC 控制器操作中不起作用的原因是什么?所有其他可选参数都有效(int、string),但它不适用于 GUID,表示“'/' 应用程序中的服务器错误。参数字典包含不可为空类型 'System.Guid' 的参数 'categoryId' 的空条目' .." 代码在两种规范(default(Guid) 和 new Guid())下都能正常编译,但会出现此错误。
  • @mare:我不知道,恐怕。另一种选择是使用Nullable&lt;Guid&gt;,可能。
【解决方案5】:

编译器非常正确; Guid.Empty 不是编译时常量。您可以尝试像这样进行方法重载:

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

【讨论】:

  • 我说我不想改变API,我试图驯服的方法有超过10个参数!
  • @Ian Ringrose,虽然我同意Guid x = default(Guid) 作为解决方案,但请记住,添加另一个函数重载不会比添加可选参数更复杂 API。无论如何,这确实是可选参数的作用。
  • @tenfour,它必须是 许多 新函数重载才能与 10 个可选参数一样!
  • 如果您有一个需要十多个参数的公共函数,也许将单个参数设为可选并不是真正的解决方案......另外,回顾最初的问题,您确实说您不想“更改 API”(就像 tenfour 指出的那样,显式重载和可选参数之间的区别在实践中是最小的)但是在参数列表的问题中没有提到是那种怪物.
  • 其实这是一个完美的问题解答。
猜你喜欢
  • 2012-05-01
  • 2011-07-29
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
  • 2010-12-01
相关资源
最近更新 更多