C # - Как я могу убедиться, что все мои структуры инициализированы? - PullRequest
6 голосов
/ 06 декабря 2008

Я пишу приложение на C #, которое будет делать обширные вычисления. Все идет вокруг базовой структуры - Value. Это в основном двойной с некоторыми дополнительными параметрами (точность и т. Д.) Это должна быть структура, потому что их будет слишком много, чтобы выделять кучу. Теперь мне нужно убедиться, что все они правильно инициализированы. Я не могу объявить явный конструктор по умолчанию, хотя мне предоставляется конструктор по умолчанию, который инициализирует все с 0, что не имеет смысла в моем домене.

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

В основном мне нужно пройти этот тест:

[Test]
public void HowDoesThisStructureInitializeByDefault()
{
   Value v = new Value(); - if this did not compile - it would have been ok!

   Assert.AreEqual(0, v.Val); - passes
   Assert.AreEqual(-1, v.Accuracy); - fails
}

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

Я почти теряю надежду, пожалуйста, помогите!

Ответы [ 5 ]

4 голосов
/ 06 декабря 2008

Почему вы не можете определить явный конструктор? Это то, что они для . Более того, почему вы думаете, что «не можете позволить себе выделение кучи»? Распределение кучи очень дешево в управляемых языках. Как вы проверили это предположение о том, что вы не можете позволить себе выделение кучи, или что выделение кучи в первую очередь дороже?

(Для типа, состоящего из "double и нескольких параметров", я подозреваю, что вы находитесь в размере, где выделение кучи на самом деле дешевле и эффективнее)

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

Но, конечно, у вас нет никаких гарантий, что люди на самом деле называют это.

Изменить: Распределение кучи в .NET в основном состоит из простой операции выталкивания стека. Это хорошо в управляемых (и сборочных) языках. Среда выполнения по существу использует большой стек в качестве кучи, поэтому каждое выделение просто увеличивает указатель стека (конечно, после проверки, что свободной памяти достаточно). Затем сборщик мусора по мере необходимости заботится об сжатии памяти.

Так что выделение кучи само по себе смехотворно дешево. Конечно, дополнительное давление ГХ может снова замедлить вас (хотя, насколько мне известно, время, необходимое для прохода ГХ, зависит только от количества живых объектов, а не от тех, которые должны быть собраны с помощью ГХ, так что их не будет » «мертвые» объекты, лежащие вокруг, могут не быть большой проблемой), но с другой стороны, распределение стека также не является бесплатным. Типы значений передаются по значению, поэтому каждый раз, когда вы передаете свой тип в качестве параметра функции или возвращаете его, необходимо сделать копию. Я не знаю, насколько велико ваше значение, но значение double равно 8 байтам, и, учитывая, что у вас есть несколько дополнительных параметров, я предполагаю, что 32 байта. Это может быть настолько большим, что дополнительное копирование, необходимое для типов значений, делает его медленнее, чем если бы вы использовали выделение кучи. Возможно.

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

3 голосов
/ 06 декабря 2008

Поля структуры инициализируются в ноль (или ноль, или в общем случае по умолчанию (T)).

Если вы хотите, чтобы начальное значение Accuracy было равно -1, вы можете реализовать свойство Accuracy так, чтобы, когда базовое поле == 0, свойство возвращало -1.

Одна возможность:

struct Value
{
  int _accuracyPlusOne;

  public int Accuracy
  { 
    get { return _accuracyPlusOne - 1; }
    get { _accuracyPlusOne= value + 1; }
  }
}
3 голосов
/ 06 декабря 2008

Вы не можете избавиться от конструктора по умолчанию (Jon Skeet, конечно, ответил, почему очень хорошо на Почему я не могу определить конструктор по умолчанию для структуры в .NET? ), но Вы можете создать фабричный класс, который позволит вам определять значения структуры с правильно инициализированными параметрами. Вы можете использовать модульные тесты с mock / verify, чтобы убедиться, что при создании новых значений вашим кодом они используют фабрику. Это будет соглашение, которое вам нужно будет применять, поскольку компилятор не будет применять его для вас.

public static class StructFactory
{
    public static Value DefaultValue()
    {
         Value v = new Value();
         v.Value = 0.0;
         v.Accuracy = 15; /* digits */
         return v;
    }
}

...

Value v = StructFactory.DefaultValue();
2 голосов
/ 06 декабря 2008

Я не думаю, что C # позволяет вам создавать конструкторы по умолчанию для типов значений. Есть несколько вопросов, связанных с вашей проблемой:

Есть способ сделать это в IL, но инициализация массивов все равно не вызовет эти конструкторы.

0 голосов
/ 06 декабря 2008

Вы надеетесь инициализировать точность до -1 с помощью конструктора по умолчанию? Я не думаю, что вы можете помешать кому-либо использовать new Value(), но вы можете добавить конструктор, который позволит вам использовать new Value(10) и инициализировать точность так, как вы хотите.

См. Страницу MSDN о [Struct Constructors] (http://msdn.microsoft.com/en-us/library/aa288208(VS.71).aspx).

Вы всегда можете добавить исключение в код, который использует вашу структуру, если вы встретите точность 0 (если это значение никогда не имеет смысла!).

...