Как я могу по умолчанию указать параметр Guid.Empty в С#?

Я хочу сказать:

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

Но компилятор жалуется, что Guid.Empty не является постоянной времени компиляции.

Поскольку я не хочу менять API, я не могу использовать:

 Nullable<Guid>

Ответ 1

Решение

Вы можете использовать new Guid() isntead

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). Компилятор может иметь только значения, зависящие от компилятора, как значения параметров метода по умолчанию (не известные только по времени).

Основная причина заключается в том, что вы не можете иметь const любого struct, в отличие от enum, например. Если вы попробуете, он не будет компилироваться.

Причина еще в том, что struct не является примитивным типом.
Список всех примитивных типов в .NET см. http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
(обратите внимание, что enum обычно наследует int, который является примитивным)

Но new Guid() тоже не является константой!

Я не говорю, что ему нужна константа. Ему нужно что-то, что можно решить во время компиляции. Empty - это поле, поэтому его значение неизвестно во время компиляции (только в самом начале времени выполнения).

Значение параметра по умолчанию должно быть известно во время компиляции, которое может быть значением const или чем-то определенным с использованием функции С#, которая делает значение известным во время компиляции, например default(Guid) или new Guid() (что решено во время компиляции для struct, поскольку вы не можете изменить конструктор struct в коде).

Пока вы можете легко предоставить default или new, вы не можете предоставить const (потому что это не примитивный тип или enum, как объяснялось выше). Поэтому, опять же, не говоря, что для необязательного параметра требуется константа, но известное значение компилятора.

Ответ 2

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(), который вы, возможно, создали. Вы не можете создать такой конструктор в типе значений в С#, но вы можете сделать это в IL.)

Вы можете использовать опцию default(Foo) для любого типа.

Ответ 3

Вы не можете использовать:

default ( Guid )?

Ответ 4

Принятый ответ не работает в 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();
    }
}

Ответ 5

Компилятор вполне корректен; Guid.Empty не является константой времени компиляции. Вы можете попробовать перегрузить метод следующим образом:

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