it-swarm-ru.tech

C # struct new StructType () против по умолчанию (StructType)

Скажи у меня есть структура

public struct Foo
{
    ...
}

Есть ли разница между

Foo foo = new Foo();

а также

Foo foo = default(Foo);

?

52
Bala R

Вы можете задаться вопросом, почему, если они абсолютно одинаковы, есть два способа сделать одно и то же.

Они не совсем одинаковы, потому что каждому ссылочному типу или типу значения гарантированно присваивается значение по умолчанию но не каждый ссылочный тип гарантированно имеет конструктор без параметров:

static T MakeDefault<T>()
{
    return default(T); // legal
    // return new T(); // illegal
}
70
Eric Lippert

Нет, оба выражения приведут к одинаковому точному результату.

Поскольку структуры не могут содержать явных конструкторов без параметров (т. Е. Вы не можете определить их самостоятельно), конструктор по умолчанию предоставит вам версию структуры со всеми значениями, обнуленными. Это то же поведение, что и default.

17
Andrew Hare

Для типов значений параметры, практически говоря, эквивалентны.

Тем не менее, я был заинтригован тем, что Jon Skeet эмпирическое исследование , в котором "инструкции" приводят к вызову конструктора по умолчанию для параметров без параметров, когда он указан в CIL (вы не можете сделать это в C #, потому что не позволю вам). Среди прочего он опробовал default(T) и new T(), где T - параметр типа. Они оказались эквивалентными; ни один из них не вызвал конструктор.

Но один случай (кажется), который он не пробовал, был default(Foo), где Foo - это фактический тип структуры.

Поэтому я взял его код для взломанной структуры и попробовал это для себя.


Оказывается, что default (Foo) не вызывает конструктор, тогда как new Foo () на самом деле делает.

Используя тип структуры Oddity, который определяет конструктор без параметров:

При отключенной оптимизации метод:

private void CallDefault()
{
    Oddity a = default(Oddity);
}

создает CIL (без nops, rets и т. д.):

L_0001: ldloca.s a
L_0003: initobj [Oddity]Oddity

тогда как метод:

private void CallNew()
{
    Oddity b = new Oddity();
}

производит:

L_0001: ldloca.s b
L_0003: call instance void [Oddity]Oddity::.ctor()

При включенной оптимизации компилятор, по-видимому, в значительной степени оптимизирует все метода CallDefault в нет, но сохраняет вызов конструктора в CallNew (для потенциальных побочных эффектов?).

14
Ani

Спецификация языка (§4.1.2 и §5.2) - ваш друг. В частности:

Для переменной value-type значение по умолчанию совпадает со значением, вычисленным конструктором по умолчанию value-type (§4.1.2).

(Курсив в оригинале.)

Обратите внимание, что это не то же самое для ссылочных типов.

Для переменной ссылочного типа значением по умолчанию является null.

Это существенно отличается от значения, созданного конструктором по умолчанию, если таковой существует.

12
jason

Ключевое слово default полезно, когда вы не знаете точный тип, и оно работает не только для структур, например, в обобщениях:

T FirstOrDefault(IEnumerable<T> source)
{
    if (...source is empty...) return default(T);
}

Это возвратит нуль для ссылочных типов, значение по умолчанию для примитивных типов (0 для чисел, false для bool), по умолчанию инициализированная структура и т. Д ...

Когда тип известен во время компиляции, нет смысла использовать default, вместо этого вы можете использовать new Foo()

5
Snowbear