简体   繁体   English

可以让结构具有默认值无效吗?

[英]Is it okay for a struct to have default value invalid?

Consider the following struct 考虑以下结构

public struct ResizeFactor
{
    public readonly float Horizontal;
    public readonly float Vertical;

    public ResizeFactor(float horizontal, float vertical)
    {
        if (horizontal <= 0)
            throw new ArgumentOutOfRangeException("...");
        if (vertical <= 0)
            throw new ArgumentOutOfRangeException("...");

        Horizontal = horizontal;
        Vertical = vertical;
    }
}

It feels like a 'value'. 感觉就像一个“价值”。 It's small and immutable. 它很小且一成不变。 It looks and feels 'struct'y. 它的外观和感觉“结构化”。

But there's the default value problem... It doesn't feel right to have ResizeFactor with Horizontal = Vertical = 0 as default value. 但是存在默认值问题...将“ Horizo​​ntal = Vertical = 0”作为默认值的ResizeFactor是不合适的。

Example: 例:

var myResizeFactor = new ResizeFactor();
// myResizeFactor.Horizontal = 0

I know I could use a class instead and just 'disable' the default parameterless constructor, but that's not really the point here. 我知道我可以改用一个类,而只是“禁用”默认的无参数构造函数,但这并不是重点。 The question is: is it legit to create such struct? 问题是:创建这样的结构是否合法? One with a invalid default value? 一个无效的默认值?

Last but not least: it this the right place to a question like this? 最后但并非最不重要的一点:这是这样的问题的正确地方吗? Or should I post somewhere else, like https://softwareengineering.stackexchange.com/ 或者我应该在其他地方发布,例如https://softwareengineering.stackexchange.com/

I would try very hard to make the default value valid, yes. 我会尽力使默认值有效,是的。 For example, you could do something like: 例如,您可以执行以下操作:

public struct ResizeFactor
{
    private readonly float horizontal;
    private readonly float vertical;

    public float Horizontal => horizontal == 0f ? 1.0f : horizontal;
    public float Vertical => vertical == 0f ? 1.0f : vertical;

    public ResizeFactor(float horizontal, float vertical)
    {
        if (horizontal <= 0)
            throw new ArgumentOutOfRangeException("...");
        if (vertical <= 0)
            throw new ArgumentOutOfRangeException("...");

        this.horizontal = horizontal;
        this.vertical = vertical;
    }
}

This means that the default internal representation has an effective value of (1f, 1f) — a no-op resize, basically. 这意味着默认内部表示形式的有效值为(1f,1f)-基本上是无操作调整大小。

We use the same approach in Noda Time where various value types can contain a reference to a time zone — which we deem to be UTC if the value is null. 我们在Noda Time中使用相同的方法,其中各种值类型可以包含对时区的引用-如果值为null,则认为该时区为UTC。

Note that this is one of the benefits of exposing properties instead of fields... the internal details become less relevant. 请注意,这是暴露属性而不是字段的好处之一...内部细节变得不那么重要。

As an aside, I think actually a "resize to 0" is entirely reasonable as a factor. 顺便说一句,我认为实际上“调整为0”是一个完全合理的因素。 After all, if you allow float.Epsilon that would resize almost anything to either 0 or very, very small anyway... is there really that much difference between that and resizing to 0? 毕竟,如果您允许float.Epsilon ,它将几乎将任何东西的大小都调整为0或非常非常小……调整大小和将其调整为0真的有那么大的区别吗?

if you omit the new keyword when declaring the struct you can apparently get a struct with uninitialized, invalid values: 如果在声明结构时省略了new关键字 ,则显然可以得到具有未初始化的无效值的结构:

When you create a struct object using the new operator, it gets created and the appropriate constructor is called. 使用new运算符创建结构对象时,将创建该对象并调用适当的构造函数。 Unlike classes, structs can be instantiated without using the new operator. 与类不同,可以在不使用new运算符的情况下实例化结构。 In such a case, there is no constructor call, which makes the allocation more efficient. 在这种情况下,没有构造函数调用,这使分配更加有效。 However, the fields will remain unassigned and the object cannot be used until all of the fields are initialized. 但是,在初始化所有字段之前,这些字段将保持未分配状态,并且无法使用该对象。

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

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