C# - 如何确保我的所有结构都已初始化?

时间:2008-12-06 18:39:42

标签: c# struct value-type

我正在用C#编写一个应用程序,它将进行大量计算。一切都围绕着基本的结构 - 价值。它基本上是一些附加参数(精度等)的两倍 它必须是一个结构体,因为会创建太多的结构来提供堆分配。 现在,我需要确保它们都已正确初始化。 我不能声明默认的显式构造函数,虽然我提供了默认构造函数,它使用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 个答案:

答案 0 :(得分:4)

为什么不能定义显式构造函数?这就是他们。 而且,为什么你认为你“买不起堆分配”?堆栈分配在托管语言中非常便宜。您是如何测试这种假设,即您无法负担堆分配,或者实际上堆分配首先是否更昂贵?

(对于由“一个双参数和几个参数”组成的类型,我怀疑你的堆大小实际上更便宜,效率更高)

在任何情况下,如果他愿意,你不能阻止用户调用值类型的默认构造函数。您所能做的就是确保存在初始化值的更好方法,例如非默认构造函数,或者由于某种原因无法创建一个值,这是一个在调用时创建和初始化值类型的函数。 / p>

但当然,你无法保证人们真正称之为。

编辑: .NET 中的堆分配基本上是只包含一个简单的堆栈推送操作。这是托管(和垃圾收集)语言的好处。运行时本质上使用一个大堆栈作为其堆,因此每个分配只是稍微增加堆栈指针(当然,在检查有足够的可用内存之后)。 然后垃圾收集器在必要时负责压缩内存。

因此堆分配本身非常便宜。当然,额外的GC压力可能会再次降低你的速度(虽然据我所知,GC通过所需的时间仅取决于活动对象的数量,而不取决于要进行GC操作的时间,因此无数次“死的“周围的物体可能不是一个大问题”,但另一方面,堆栈分配也不是免费的。值类型按值传递,因此每次将类型作为参数传递给函数或返回它时,都必须进行复制。我不知道你的值有多大,但是一个double是8个字节,并且假设你有一些额外的参数,我将假设32个字节。那个可能太大了,以至于值类型所需的额外复制使得它比使用堆分配时要慢。也许

如您所见,价值型和参考型都有优势。在你的情况下,我不能说哪一个更快,但如果我是你,我会非常小心地做出这种假设。如果可能,请构造代码,以便在reference-和valuetype实现之间切换,看看哪种方法效果最好。或者,编写较小的测试以尝试预测每个测试的大规模执行情况。

答案 1 :(得分:3)

你无法摆脱默认的构造函数(Jon Skeet,当然,在Why can't I define a default constructor for a struct in .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 :(得分:3)

结构字段初始化为零(或空,或一般默认(T))。

如果希望Accuracy的初始值为-1,则可以实现Accuracy属性,以便当基础字段== 0时,属性返回-1。

一种可能性:

struct Value
{
  int _accuracyPlusOne;

  public int Accuracy
  { 
    get { return _accuracyPlusOne - 1; }
    get { _accuracyPlusOne= value + 1; }
  }
}

答案 3 :(得分:2)

我认为C#不允许您在值类型上创建默认构造函数。 您的问题有几个问题:

有一种方法可以在IL中执行,但初始化数组仍然不会调用这些构造函数。

答案 4 :(得分:0)

您是否希望使用默认构造函数将精度初始化为-1?我不认为你可以阻止某人使用new Value(),但你可以添加一个构造函数,让你使用new Value(10)并按照你想要的方式初始化。

请参阅有关[Struct Constructors]的MSDN页面(http://msdn.microsoft.com/en-us/library/aa288208(VS.71).aspx)

如果你遇到精度为0的话,你总是可以在使用你的结构的代码中抛出异常(如果这个值没有意义!)。