简体   繁体   English

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

[英]How do you specify what a default state of a derived struct should be in C#?

I've seen different questions on SO about not being able to use parameterless constructors or not setting field initializers, but I think my question kind of goes a step beyond that. 我在SO上看到了关于无法使用无参数构造函数或不设置字段初始化器的不同问题,但我认为我的问题远远超出了这一点。

What I would like to know is, how would I go about setting up the "default" value of a struct I need to define? 我想知道的是,我将如何设置我需要定义的结构的“默认”值? Say I'm making a TaxID struct, and the default value needs to be 999-99-9999 for whatever reason. 假设我正在制作TaxID结构,无论出于何种原因,默认值都必须为999-99-9999。 This is already done with other structs in .NET, namely the DateTime. 这已经在.NET中的其他结构中完成,即DateTime。 Any time you declare a DateTime the value is immediately set to Jan 1 0001 12:00 AM. 每当您声明DateTime时,该值立即设置为Jan 1 0001 12:00 AM。 Why does it get set to this value and not 0/0/0000 00:00:0000 AM? 为什么它设置为此值而不是0/0/0000 00:00:0000 AM? There must be something going on behind the scenes that makes the value actually make "sense" at it's "default", even given the restrictions put on us by c# with regards to structs. 必须在幕后发生一些事情,使得这个值实际上在它的“默认”中变得“有意义”,即使考虑到结构对c#的限制。

In general, this should be avoided. 一般来说,这应该避免。 If you need to require a good, default case which would require construction, you should consider changing to a class. 如果您需要一个需要构造的良好的默认情况,您应该考虑更改为一个类。

One of the core design guidelines for structs is: Do ensure that a state where all instance data is set to zero, false, or null (as appropriate) is valid. 结构的核心设计指南之一是:确保将所有实例数据设置为零,false或null(视情况而定)的状态有效。

For details, see the design guidelines . 有关详细信息,请参阅设计指南


I just looked this section up in the design guidelines 2nd edition, and they have an example in detail there using properties and non-conventional overrides to work around this, as well. 我只是在第2版的设计指南中看了这一部分,他们有一个详细的例子,使用属性和非常规覆盖来解决这个问题。 The basic concept was to save the value privately in a way that 0 is the "good default", and do some form of transform in every property and method override (including ToString). 基本概念是以0是“良好默认”的方式私下保存值,并在每个属性和方法覆盖中执行某种形式的转换(包括ToString)。 In their case, they used a positive integer as an example, and always save curVal-1 in the private member, so the default value (0) is treated like a value of 1. They added a constructor with an int val, and save value-1 internally, etc. 在他们的例子中,他们使用正整数作为示例,并始终将curVal-1保存在私有成员中,因此默认值(0)被视为值为1.他们添加了一个带有int val的构造函数,并保存内部价值-1等

This seems like a lot of hidden, unexpected overhead, though - so I'd personally still recommend (and use) a class in this case. 这似乎是很多隐藏的,意外的开销 - 所以我个人仍然建议(并使用)这种情况下的类。

--- Edit in response to comments --- ---编辑以回应评论---

DateTime, as your example, is the way it is because 0 == 1/1/0001 at Midnight. 作为您的示例,DateTime是它的方式,因为在午夜0 == 1/1/0001。 DateTime uses a single, ulong to represent ticks from 1/1/0001. DateTime使用单个ulong来表示1/1/0001的刻度。 That is why ( from here ): 这就是为什么( 从这里 ):

"The DateTime value type represents dates and times with values ranging from 12:00:00 midnight, January 1, 0001 Anno Domini (Common Era) through 11:59:59 PM, December 31, 9999 AD (CE) " “DateTime值类型表示日期和时间,值范围为午夜12:00,1月1日,000 Anno Domini(公共时代)到公元9999年12月31日晚上11:59:59”(CE)

This is the full range of ulong in ticks. 这是蜱中的全方位ulong。 A "0" in the struct of DateTime is treated as 1/1/0001 when you convert to a string - the values aren't 1 + 1 + .... - it's a single 0. 当您转换为字符串时,DateTime结构中的“0”被视为1/1/0001 - 值不是1 + 1 + .... - 它是单个0。

Any time you declare a DateTime the value is immediately set to Jan 1 0001 12:00 AM. 每当您声明DateTime时,该值立即设置为Jan 1 0001 12:00 AM。 Why does it get set to this value and not 0/0/0000 00:00:0000 AM? 为什么它设置为此值而不是0/0/0000 00:00:0000 AM? There must be something going on behind the scenes that makes the value actually make "sense" at it's "default", even given the restrictions put on us by c# with regards to structs. 必须在幕后发生一些事情,使得这个值实际上在它的“默认”中变得“有意义”,即使考虑到结构对c#的限制。

More likely it implicitly initializes a ticks field to default(int) = 0, and 0 ticks means DateTime.MinValue when you go to get the value. 更可能的是它隐式地将ticks字段初始化为default(int) = 0,并且当你去获取值时,0 ticks表示DateTime.MinValue

Nothing sinister is going on. 没有任何险恶的事情发生。 The internal representation of a DateTime is the number of 100 nanosecond "ticks" since 12:00:00 midnight, January 1, 0001 Anno Domini. DateTime的内部表示是自0001年1月1日午夜12:00:00 Anno Domini以来100纳秒“滴答”的数量。 When the DateTime is created, the tick count is zero. 创建DateTime时,滴答计数为零。 If you look at DateTime with Ildasm, you will see it's a bit more complicated than that, but you get the idea. 如果你用Ildasm看一下DateTime,你会发现它比这复杂一点,但是你明白了。 :) :)

You cannot declare a default constructor in a C# struct. 您不能在C#结构中声明默认构造函数。 You can simulate this behavior by creating a private field and writing a property to return the default value if it's 1/1/1 您可以通过创建私有字段并编写属性来模拟此行为,如果它是1/1/1,则返回默认值

Just for completeness: 只是为了完整性:

Value types in C# (including arrays, structs, enums) are always initialized to all zeros. C#中的值类型(包括数组,结构,枚举)始终初始化为全零。 Reference types are also initially zero, better know as null . 引用类型最初也为零,更好地称为null

In case of enums, zero is the default value, and is always a possible value even if it's not a defined in the enum. 对于枚举,零是默认值,并且即使它不是枚举中的定义,也始终是可能的值。 Personally, I usually define 0 as None, Empty, Unknown or something similar: 就个人而言,我通常将0定义为None,Empty,Unknown或类似的东西:

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

In case of arrays, if it's an array of reference types, they are all initially null (which you can think of as a pointer to address 0). 对于数组,如果它是一个引用类型数组,它们最初都是null (您可以将其视为指向地址0的指针)。 If it's an array of value types, they are all initially zero or the equivalent (see other answers about DateTime.Ticks and why a "zeroed" DateTime is equal to 1/1/0001 12:00am). 如果它是一个值类型的数组,它们最初都是零或等价的(参见关于DateTime.Ticks其他答案以及为什么“归零”DateTime等于1/1/0001 12:00 am)。

Coming back to structs: the same applies. 回到结构:同样适用。 They will always have a default parameterless constructor and you cannot avoid this. 它们将始终具有默认的无参数构造函数 ,您无法避免这种情况。 All value type members will initially be zero (or equivalent) and all reference type members will be null . 所有值类型成员最初将为零(或等效),并且所有引用类型成员都将为null Think about int, short, decimal, char, DateTime (ahem), TimeSpan, Size, Point, Rectangle, Color, Guid... they are all initialized to all zeros. 想想int,short,decimal,char,DateTime(ahem),TimeSpan,Size,Point,Rectangle,Color,Guid ......它们都被初始化为全零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM