如何防止调用结构的默认构造函数?

How to prevent a struct's default constructor to be called?

有什么方法可以防止调用结构的默认构造函数吗?

我的项目中有几个结构,其中一些我不能让默认构造函数在任何情况下都被调用(这会在我的代码中导致很多不需要的行为)。

PS.: 任何在编码时仅指示我正在实例化某些特殊结构(无法使用默认构造函数实例化)的解决方案 "wrongly" 对我来说都很好。对于我的情况,一个简单的编译器警告就足够了!

你不能。

天生,

  • struct 的所有字段都必须初始化为某个值。
  • a struct 不能有无参数构造函数
  • 无参数构造函数会被隐式调用,没有办法解决。

如果您需要这样的行为,请使用 class 或检查您的设计。

正如 Aybe 所指定的那样,您不能这样做,但您可以在结构中添加一个字段,例如 IsInitialized,它将默认为 false,并使代码使用它来验证值并在 false 时抛出。

当您处理结构时,C# 想要确保您已经初始化了结构的所有字段。

一个选项是提供一个构造函数,它首先调用默认构造函数,然后再进行自定义初始化:

 public S(int x) : this()
 {
     /* custom initialization logic */
 }

另一种选择是提供一个构造函数,该构造函数可证明在其自身主体中初始化结构的所有字段,在这种情况下,您无需链接默认构造函数:

 public S(int x)
 {
     this.X = x;
     /* custom initialization logic */
 }

另一种选择是跳过调用构造函数,而是在实际使用之前手动初始化结构:

S s;
s.X = 5;

在上述选项中,只有第一个执行对默认构造函数的逻辑调用,而其他两个跳过调用。

坏消息是,在幕后,出于安全原因,CLR 将始终为您提供零初始化内存,这几乎完全等同于调用 C# 默认构造函数。你可以这样观察:

S s;
S* ptr = &s;
int x = (*ptr).X;
Console.WriteLine(x); // will print 0

好消息是,在大多数情况下,这并不重要。 C# 默认构造函数并不是 CLR 意义上的真正构造函数。任何 T : struct 的表达式 new T() 等同于 default(T),这只是一种表达获取类型 T 的零初始化实例的方式。这也是为什么您不能将其设为私有或向其添加自定义逻辑的原因。

因此,C# 默认结构构造函数不能有任何逻辑上可从外部观察到的副作用。这给我们带来了一个问题:您想要避免什么样的影响?

请记住,如果您的问题是您的结构对于全零位模式无效并且您担心某些客户端代码可能会尝试那样使用它,那么有一个解决方法:

struct S
{
    private bool _isValid;
    /* rest of your struct */
}

任何零初始化的结构都不会设置其有效性标志,一旦对您的结构执行任何操作(您可以控制),您就可以使用它来抛出异常。

毕竟,如果出于任何原因您仍然需要一个以某种方式跳过调用任何构造函数(无论是真实的还是明显的构造函数)的结构实例,您将不得不自己为该结构分配一些内存:

S* ptr = (S*) Marshal.AllocHGlobal(Marshal.SizeOf<S>());

您现在可以使用 (*ptr).Xptr->X 形式的表达式直接读取和写入该结构。