Як я можу встановити параметр Guid.Empty в C #?


178

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

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

Але компілятор скаржиться, що Guid.Empty не є константою часу компіляції.

Оскільки я не хочу змінювати API, я не можу використовувати:

 Nullable<Guid>


Що не так з переходом на Nullable<Guid> optional = null(або більш короткочасне Guid? optional = null)? Будь-які Посібники, які зараз передані до нього, виконуватимуться без будь-яких змін коду, необхідних взагалі.
NH.

Відповіді:


235

Рішення

Ви можете використовувати 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). Компілятор може мати лише відомі для компілятора значення як параметри методу за замовчуванням (не відомі лише для виконання).

Першопричиною є те, що ви не можете мати constжодного struct, на відміну від, 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конструктор у код).

Незважаючи на те, що ви можете забезпечити defaultабо newлегко, ви не можете надати const(тому що це не примітивний тип чи enumпояснення, описане вище). Отже, знову ж таки, не кажучи, що необов'язковий параметр сам по собі потребує постійного, але відомого компілятора значення.


5
Ну, воно не потребує нормального постійного вираження - наприклад, new Guid()це не постійний вираз. Специфікація C # досить чітко визначає, що дозволяється, включаючи константи , але не обмежуючись ними. (Просто щоб бути ясно, що ефективно це постійне час компіляції, просто не «константа» в C # Spec термінів).
Джон Скіт

3
Прочитайте частину Пояснення у моїй відповіді. Додано, щоб відповісти на цю частину.
Мелігія

Гарне пояснення. Дякую!
Дарил

Ви можете використовувати лише defaultсьогодні :)
Joshit

151

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.)

Ви можете використовувати цю default(Foo)опцію для будь-якого типу.


Тепер, чому повідомлення про помилку компілятора не каже мені цього, компілятор може перевірити випадок Guid.Empty і дати більш корисне повідомлення.
Ян Рінроуз

4
@Ian Ringrose: Я не думаю, що компілятор взагалі не повинен мати типових повідомлень, якщо чесно.
Джон Скіт

2
Якщо встановити параметр за замовчуванням для нового об'єкта, створюється новий об'єкт кожного разу, коли метод викликається в PHP; але створює лише один об'єкт для всієї програми в Python. Дійсно, я вважаю це одним із небагатьох недоліків дизайну Python . Я дещо радий, що C # (і VB.Net) уникнув цього питання, просто заборонивши нові об’єкти за типовими параметрами ... хоча в PHP є такі можливості, коли це дуже добре.
BlueRaja - Danny Pflughoeft

1
що може бути причиною того, що ця сама робота не працюватиме в дії контролера ASP.NET MVC? Всі інші необов’язкові параметри працюють (int, string), але він не працює для GUID, говорить "Помилка сервера в" / "Застосування. Словник параметрів містить нульовий запис для параметра" categoryId "ненульового типу" System.Guid '.. "Код добре поєднується з обома специфікаціями (за замовчуванням (Guid) та з новим Guid ()), але видає цю помилку.
кобила

@mare: Не знаю, боюся. Іншим варіантом було б використання Nullable<Guid>потенційно.
Джон Скіт

18

Не можете використовувати:

default ( Guid ) ?


1
Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
рекурсивна

4
Вибачте, я не мав на увазі ?? як оператор, але як наголошений знак питання - я редагую!
Нік

9

Прийнята відповідь не працює в 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> - досить справедливо
Majix

Якщо ви не хочете явно призначити параметр "необов'язковий" з порожнім значенням Guid, я думаю, що це найбільш природний спосіб визначення необов'язкового параметра типу Guid.
Гонсало Мендес

4

Компілятор цілком коректний; Guid.Emptyне є константою часу компіляції. Ви можете спробувати зробити перевантаження методу таким чином:

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

Я сказав, що не хочу змінювати API, метод, який я намагаюся приручити, має понад 10 парм!
Ян Рінроуз

@Ian Ringrose, хоча я згоден з Guid x = default(Guid)рішенням, пам’ятайте, що додавання іншої функції перевантаження не ускладнює API більше, ніж додавання необов'язкового аргументу. Це дійсно те, що необов'язковий аргумент так чи інакше.
десять четвертого

@tenfour, потрібно буде багато нових перевантажень функції, щоб зробити те саме, що 10 необов’язкових пар!
Ян Рінроуз

Якщо у вас є загальнодоступна функція, яка вимагає понад десяти параметрів, можливо, один аргумент необов’язковий насправді не виправлення ... Крім того, озираючись на початкове запитання, ви дійсно говорите, що не хочете "змінювати API "(і, як вказує десять разів, різниця між явним перевантаженням і необов'язковим аргументом на практиці мінімальна), але в питанні про список параметрів такого типу монстра немає згадки.
CVn

Власне, це ідеальна відповідь на проблему.
ПКД
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.