如何指定派生结构的默认状态应该在C#中?

我已经看到了关于不能使用无参数构造函数或不设置字段初始化器的SO的不同问题,但我认为我的问题远远超出了这一点。

我想知道的是,我将如何设置我需要定义的结构的“默认”值? 假设我正在制作TaxID结构,无论出于何种原因,默认值都需要为999-99-9999。 这已经在.NET中的其他结构中完成,即DateTime。 每当您声明DateTime时,该值立即设置为Jan 1 0001 12:00 AM。 为什么它设置为此值而不是0/0/0000 00:00:0000 AM? 必须在幕后发生一些事情,使得这个值实际上在它的“默认”上变得“有意义”,即使考虑到c#对结构的限制。

一般来说,这应该避免。 如果您需要一个需要构造的良好的默认情况,您应该考虑更改为一个类。

结构的核心设计指南之一是:确保将所有实例数据设置为零,false或null(视情况而定)的状态有效。

有关详细信息,请参阅设计指南 。


我只是在设计指南第2版中看到了这一部分,他们有一个详细的例子,使用属性和非常规覆盖来解决这个问题。 基本概念是以0为“良好默认值”的方式私下保存值,并在每个属性和方法覆盖中执行某种forms的转换(包括ToString)。 在他们的例子中,他们使用正整数作为示例,并始终将curVal-1保存在私有成员中,因此默认值(0)被视为值为1.他们添加了一个带有int val的构造函数,并保存内部价值-1等

这看起来像很多隐藏的,意外的开销 – 所以我个人仍然建议(并使用)这种情况下的类。

—编辑以回应评论—

作为您的示例,DateTime是它的方式,因为在午夜0 == 1/1/0001。 DateTime使用单个ulong来表示1/1/0001的刻度。 这就是为什么( 从这里 ):

“日期时间值类型表示日期和时间,值范围为午夜12:00,1月1日,000 Anno Domini(普通时代)至公元9999年12月31日晚上11:59:59”(CE)

这是蜱中的全系列ulong。 当您转换为字符串时,DateTime结构中的“0”被视为1/1/0001 – 值不是1 + 1 + …. – 它是单个0。

每当您声明DateTime时,该值立即设置为Jan 1 0001 12:00 AM。 为什么它设置为此值而不是0/0/0000 00:00:0000 AM? 必须在幕后发生一些事情,使得这个值实际上在它的“默认”上变得“有意义”,即使考虑到c#对结构的限制。

更可能的是它隐式地将ticks字段初始化为default(int) = 0,并且当你去获取值时,0 ticks表示DateTime.MinValue

没有任何险恶的事情发生。 DateTime的内部表示是自0001年1月1日午夜12:00:00 Anno Domini以来100纳秒“滴答”的数量。 创建DateTime时,滴答计数为零。 如果你用Ildasm看看DateTime,你会发现它比这复杂一点,但你明白了。 🙂

您不能在C#结构中声明默认构造函数。 您可以通过创建私有字段并编写属性来模拟此行为,如果它是1/1/1,则返回默认值

只是为了完整性:

C#中的值类型(包括数组,结构,枚举)始终初始化为全零。 引用类型最初也为零,更好地称为null

对于枚举,零是默认值,并且即使它不是枚举中定义的,也始终是可能的值。 就个人而言,我通常将0定义为None,Empty,Unknown或类似的东西:

 enum MyEnum { A = 1, B = 2, C = 3 }; // ... MyEnum value = new MyEnum(); // value has a nameless 0 

对于数组,如果它是一个引用类型数组,它们最初都是null (您可以将其视为指向地址0的指针)。 如果它是一个值类型的数组,它们最初都是零或等价的(参见关于DateTime.Ticks其他答案以及为什么“归零”DateTime等于1/1/0001 12:00 am)。

回到结构:同样适用。 它们将始终具有默认的无参数构造函数 ,您无法避免这种情况。 所有值类型成员最初将为零(或等效),并且所有引用类型成员都将为null 。 想想int,short,decimal,char,DateTime(ahem),TimeSpan,Size,Point,Rectangle,Color,Guid ……它们都被初始化为全零。