Почему локальная переменная типа CancellationToken не нуждается в инициализации?

Я использую VisualStudio 2017 в проекте, предназначенном для .NET Framework 4.6.1.

Играя с Task, CancellationToken и локальным методом, я пришел к такому коду:

class Program
{
    static void Main(string[] args)
    {
        CancellationToken o;
        Console.WriteLine(o);
    }
}

Который компилируется. Теперь, если вы измените тип o на int или string, он не будет компилироваться, выдавая ошибку:

Локальная переменная 'o' может быть не инициализирована перед доступом.

Я попытался декомпилировать CancellationToken и скопировал код в структуру с именем MyCancellationToken. Это тоже не скомпилируется.

Единственный случай, когда мне удалось скомпилировать, — это пустая структура или структура, содержащая CancellationToken.

struct EmptyStruct
{
}

struct MagicStruct
{
    public CancellationToken a;
}

class Program
{
    static void Main(string[] args)
    {
        EmptyStruct a;
        MagicStruct b;
        Console.WriteLine(a);
        Console.WriteLine(b);
    }
}
  • Почему CancellationToken не нуждается в инициализации?
  • Какие другие типы не нуждаются в инициализации?

Забавный факт: если вы смешаете это с локальной функцией, вы можете написать это:

class Program
{
    static void Main(string[] args)
    {
        Work();

        CancellationToken o;

        void Work() => Console.WriteLine(o);
    }
}

Который компилируется.


person Orace    schedule 11.04.2018    source источник
comment
тогда я ошибаюсь в этом случае   -  person Pranay Rana    schedule 11.04.2018
comment
@Fildor: я думаю, дело в том, что он носит всеобъемлющий характер. Это не работает, если это структура. Это не работает, если это класс. Они не приравниваются друг к другу, они используются в качестве примеров, которые должны охватывать все существующие типы объектов (структуры и классы).   -  person Chris    schedule 11.04.2018
comment
Недавно на SO был вопрос об этом. Это преднамеренное отклонение компилятора от спецификации (в спецификации сказано, что вы должны получить сообщение об ошибке), когда структура в другой сборке содержит только частные поля ссылочного типа. Позвольте мне посмотреть, смогу ли я найти этот другой вопрос.   -  person    schedule 11.04.2018
comment
См. документы. .microsoft.com/en-us/dotnet/csharp/programming-guide/ В отличие от классов, структуры могут создаваться без создания новых... Цитата: Описание В этом примере демонстрируется уникальная функция к структурам. Он создает объект CoOrds без использования оператора new. Если вы замените слово struct словом class, программа не скомпилируется.   -  person Fildor    schedule 11.04.2018
comment
@Chris Если так выразиться, то да, это имеет смысл.   -  person Fildor    schedule 11.04.2018
comment
@hvd, действительно работает   -  person Orace    schedule 11.04.2018
comment
Другой вопрос был о Span<T>. Орас, можно ли закрыть этот вопрос как дубликат или вас интересуют некоторые вещи, на которые это не отвечает?   -  person    schedule 11.04.2018
comment
@Fildor Потому что почему CancellationToken не нужна инициализация? и почему Span<T> не нуждается в инициализации? в основном один и тот же вопрос и имеют точно такой же ответ.   -  person    schedule 11.04.2018
comment
@Fildor Здесь точно такой же глюк. CancellationToken не является пустой структурой. Имеет приватное поле ссылочного типа.   -  person    schedule 11.04.2018
comment
@hvd. Ааа, да. Прочитал еще раз, теперь вижу.   -  person Fildor    schedule 11.04.2018
comment
Ответ здесь stackoverflow.com/questions/4945474/ Кажется, это компилятор С#. Но я не могу найти никакой информации о том, как структура назначается для автоинициализации категории в зависимости от ее полей.   -  person Evgeny Gorbovoy    schedule 11.04.2018
comment
C# при компиляции проверяет внутреннюю структуру структуры и, если в ней нет примитивных полей, производит для этого автоинициализацию. Полезно, но официальной информации не нашел(   -  person Evgeny Gorbovoy    schedule 11.04.2018
comment
@EugeneGorbovoy На самом деле это ответный вопрос   -  person Orace    schedule 11.04.2018
comment
Спасибо за подтверждение, закрыто.   -  person    schedule 11.04.2018
comment
Подождите, так что на самом деле происходит? Я нашел только ошибку по этому поводу: github.com/dotnet/roslyn/pull/25886/ файлов А где вообще информация, когда я могу использовать автоматическую инициализацию, а когда нет?   -  person Evgeny Gorbovoy    schedule 11.04.2018
comment
@EugeneGorbovoy Я думаю, вы путаете поля класса с полями структуры. Поля класса автоматически инициализируются default (для любого типа, типа значения или ссылочного типа). Поля структуры вообще не должны быть автоматически инициализированы.   -  person    schedule 11.04.2018
comment
@hvd Я говорю не об инициализации полей, а об инициализации переменных. Я говорю - в случае CancellationToken o; - компилятор производит инициализацию за вас (в том числе и в случае пустой структуры), это видно после дизассемблирования. Но почему оно это делает?   -  person Evgeny Gorbovoy    schedule 11.04.2018
comment
@EugeneGorbovoy Пустые структуры обрабатываются так же, как и все другие структуры. Они считаются инициализированными, как только всем полям присвоено значение. Просто для пустых структур это происходит сразу, даже без присваивания. Это отличается от того, что происходит с CancellationToken.   -  person    schedule 11.04.2018
comment
Так почему же CancellationToken или span считаются инициализированными, и собственно где документация по этому поводу?   -  person Evgeny Gorbovoy    schedule 11.04.2018
comment
@EugeneGorbovoy Спецификация: A Переменная struct_type считается определенно назначенной, если каждая из ее переменных экземпляра считается определенно назначенной.   -  person user4003407    schedule 11.04.2018