Есть ли способ инициализировать члены структуры без использования конструктора? - PullRequest
12 голосов
/ 17 ноября 2011

У меня есть struct, который содержит два списка:

struct MonthData
{
   public List<DataRow> Frontline;
   public List<DataRow> Leadership;
}

Тем не менее, я хочу инициализировать оба при создании структуры.Если я попытаюсь:

struct MonthData
{
   public List<DataRow> Frontline = new List<DataRow>();
   public List<DataRow> Leadership = new List<DataRow>();
}

Тогда я получу:

Error   23  'MonthData.Frontline': cannot have instance field initializers in structs
...

Поскольку структуры не могут иметь конструкторов без параметров, я не могу просто установить это в конструкторе.Пока я вижу только следующие параметры:

  1. Инициализировать оба свойства при создании экземпляра MonthData
  2. Использовать класс вместо структуры
  3. Создатьконструктор с параметром и используйте его
  4. Создание методов получения и установки для свойств, которые лениво инициализируют их.

Какой рекомендуемый подход для этого?Сейчас я думаю, что сделать это занятие - лучшая идея.

Ответы [ 5 ]

7 голосов
/ 17 ноября 2011

В любом случае вы используете ссылочные типы (List<T>) в своей структуре, поэтому использование структуры в качестве типа значения не будет иметь для меня никакого смысла.Я бы просто пошел с классом.

7 голосов
/ 17 ноября 2011

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

  struct MonthData 
  {    
      public List<DataRow> Frontline;
      public List<DataRow> Leadership; 
      private MonthData(List<DataRow> frontLine = null, 
                        List<DataRow> leadership = null)
      { 
         Frontline = frontLine?? new List<DataRow>();
         Leadership = leadership?? new List<DataRow>();  
      }
      public static MonthData Factory(
          List<DataRow> frontLine= null, 
          List<DataRow> leadership= null)
      { return new MonthData(frontLine, leadership); }
  } 
7 голосов
/ 17 ноября 2011

Вместо этого вы должны использовать класс.От MSDN :

Как правило, классы используются для моделирования более сложного поведения или данных, которые предназначены для изменения после создания объекта класса.Структуры лучше всего подходят для небольших структур данных, которые содержат в основном данные, которые не предназначены для изменения после создания структуры.

1 голос
/ 17 ноября 2011

Было бы неплохо, если бы CLR позволил гарантировать, что для объектов структурного типа может быть запущен некоторый код инициализации, прежде чем они станут видимыми для чего-либо вне такого кода.Это было бы возможно сделать даже при создании массива структурного типа, передав CLR по ссылке на все отдельные элементы массива, прежде чем ссылка на сам массив была открыта где-либо.К сожалению, это привело бы к неловкой ситуации, если бы при создании массива возникло исключение.Если бы у конструкторов не было побочных эффектов, проблем не было бы - просто отбросить массив и сделать вид, что даже успешно созданных объектов никогда не было.Конструкторы с побочными эффектами, однако, могут вызвать некоторые трудности.

Поскольку, однако, нет способа инициализировать структуры при построении, и, следовательно, нет хорошего способа достижения семантики типа значения с объектами, требующими инициализации.Сожалею.Даже если семантика значения-типа будет более подходящей для вашего типа (как это было бы гораздо чаще, чем некоторые считают), вам придется использовать ссылочный тип, если необходима инициализация.Ленивая инициализация структур на самом деле не работает.Например, если у вас есть словарьназывается MyDict, повторный доступ к MyDict («Джордж»). FrontLine будет генерировать новый список.Противный.

Изменчивые структуры не являются злом;Я, во всяком случае, один из их сильных защитников.Тем не менее, есть некоторые ограничения в обработке .net изменяемых структур в .net, и, таким образом, существует много обстоятельств, когда семантика типа значения была бы уместной, но ограничения .net делают невозможным правильное предоставление такой семантики.

1 голос
/ 17 ноября 2011

Нет способа сделать это с помощью конструктора.CLR может и будет создавать экземпляры структур, просто инициализируя память нулем и избегая любых издержек ctor.Однако вы можете воспользоваться этими знаниями и создать инициализированные свойства задержки, которые имеют тот же наблюдаемый эффект.

Например:

struct MonthData {  
  private bool m_initialized;
  private List<DataRow> m_frontLine;
  private List<DataRow> m_leaderShip;

  public List<DataRow> FrontLine {
    get {
      EnsureInitialized(); 
      return m_frontLine;
    }
  }

  public List<DataRow> LeaderShip {
    get {
      EnsureInitialized(); 
      return m_leaderShip;
    }
  }

  void EnsureInitialized() {
    if (!m_initialized) {
      m_initialized = true;
      m_frontLine = new List<DataRow>();
      m_leaderShip = new List<DataRow>();
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...