C # записывает значение параметра конструктора по умолчанию пустой IEnumerable

#c# #parameter-passing #default #record #enumerable

#c# #передача параметров #По умолчанию #запись #перечисляемый

Вопрос:

Я конвертирую этот класс

 public class MyClass
{
    public IEnumerable<string> Strings { get; }

    public MyClass(IEnumerable<string>? strings = null)
    {
        Strings = strings ?? new List<string>();
    }
}
 

В запись. В настоящее время у меня есть это:

 public record MyRecord(IEnumerable<string>? strings = null);
 

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

Ответ №1:

Поскольку IEnumerable<string> это ссылочный тип, единственным возможным параметром по умолчанию является null . Там нет абсолютно ничего другого, что вы могли бы вставить туда. Но! Вы можете ссылаться на свойство из основного конструктора при инициализации явно объявленного автоматического свойства «длинной формы». Это позволит вам объединить значение по мере его присвоения свойству.

 public record MyRecord(IEnumerable<string>? Strings = null)
{
    public IEnumerable<string> Strings { get; init; } = Strings ?? Enumerable.Empty<string>();
} 
 

См. SharpLab

Это фактически создает конструктор для вашей записи, аналогичный тому, который у вас был изначально. Вот что генерирует приведенная выше ссылка (с обнуляемыми атрибутами, преобразованными обратно ? ) для конструктора:

 public MyRecord(IEnumerable<string>? Strings = null)
{
    <Strings>k__BackingField = Strings ?? Enumerable.Empty<string>();
    base..ctor();
}
 

Он немного более подробный / не такой компактный, как однострочный, но это единственный способ выполнить то, что вы просите, с помощью a record , и он по-прежнему короче, чем не record версия.

Также обратите внимание, что если вы посмотрите на сгенерированный код, свойство в конечном итоге объявляется ненулевым, в то время как параметр конструктора имеет значение null . Сравните это с однострочной версией, с которой вы начали, где сгенерированный параметр будет иметь значение null, чтобы соответствовать объявлению основного конструктора. В этом решении вы можете изменить это поведение (если вам нужно) и явно пометить свойство длинной формы nullable.

Комментарии:

1. Похоже, не очень хорошо работает с параметрами с нулевым значением — C # настаивает на том, что параметр не может быть bool? когда поле является bool .