C# - 调用具有所有默认参数的结构构造函数

Mic*_*nni 17 c# struct optional-parameters default-constructor

今天我在创建一个struct包含大量数据的时候遇到了这个问题.这是一个例子:

public struct ExampleStruct
{
    public int Value { get; private set; }

    public ExampleStruct(int value = 1)
        : this()
    {
        Value = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来很好,花花公子.问题是当我尝试使用此构造函数而未指定值并希望对参数使用默认值1时:

private static void Main(string[] args)
{
    ExampleStruct example1 = new ExampleStruct();

    Console.WriteLine(example1.Value);
}
Run Code Online (Sandbox Code Playgroud)

此代码输出0但不输出1.原因是所有结构都具有公共参数构造函数.所以,就像我调用this()我的显式构造函数一样,在Main同样的事情发生在new ExampleStruct()实际调用ExampleStruct()但不调用的地方ExampleStruct(int value = 1).因为它这样做,它使用int的默认值为0 Value.

更糟糕的是,我的实际代码是检查该int value = 1参数是否在构造函数中的有效范围内.将其添加到ExampleStruct(int value = 1)上面的构造函数中:

if(value < 1 || value > 3)
{
    throw new ArgumentException("Value is out of range");
}
Run Code Online (Sandbox Code Playgroud)

因此,正如它现在所说的那样,默认构造函数实际上创建了一个在我需要它的上下文中无效的对象.任何人都知道如何:

  • A.调用ExampleStruct(int value = 1)构造函数.
  • B.修改如何为ExampleStruct()构造函数填充默认值.
  • C.其他一些建议/选择.

另外,我知道我可以使用这样的字段而不是我的Value属性:

public readonly int Value;
Run Code Online (Sandbox Code Playgroud)

但我的理念是私下使用领域,除非他们是conststatic.

最后,我使用a struct而不是a class的原因是因为它只是一个保存非可变数据的对象,应该在构造时完全填充,并且当作为参数传递时,不应该是null(因为它通过值传递为a struct),这是struct的设计目的.

Jam*_*are 29

实际上,MSDN有一些很好的指导 struct

如果类型的实例很小并且通常是短暂的或者通常嵌入在其他对象中,则考虑定义结构而不是类.

除非类型具有以下所有特征,否则不要定义结构:

它逻辑上表示单个值,类似于基本类型(整数,双精度等).

它的实例大小小于16个字节.

这是不可改变的.

它不必经常装箱.

请注意,它们是考虑a的考虑因素struct,而且它永远不是"这应该始终是一个结构".这是因为使用a的选择struct会产生性能和使用影响(正面和负面),应谨慎选择.

特别要注意的是,他们不推荐struct大于16字节的东西(那么复制成本比复制参考成本更高).

现在,对于你的情况,除了创建一个工厂struct为你在默认状态下生成一个工厂或者trick在你的属性中做某种事情以便在第一次使用时初始化时,除此之外没有其他好办法.

struct应该记住,a 应该工作为new X()== default(X),也就是说,新构造的struct将包含其所有字段的默认值struct.这很明显,因为C#不会让你为a定义一个无参数构造函数struct,尽管很奇怪它们允许所有参数默认没有警告.

因此,我实际上建议你坚持使用a class并使其成为不可变的,并检查null它传递给它的方法.

public class ExampleClass
{
    // have property expose the "default" if not yet set
    public int Value { get; private set; }

    // remove default, doesn't work
    public ExampleStruct(int value)
    {
        Value = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您出于其他原因绝对必须拥有struct- 但请考虑struct复制演员等的成本- 您可以这样做:

public struct ExampleStruct
{
    private int? _value;

    // have property expose the "default" if not yet set
    public int Value
    {
        get { return _value ?? 1; }
    }

    // remove default, doesn't work
    public ExampleStruct(int value)
        : this()
    {
        _value = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,默认情况下,Nullable<int>将是null(即HasValue == false),因此如果这是真的,我们还没有设置它,并且可以使用null-coalescing运算符来返回我们的默认值1.如果我们没有在构造函数中设置它,这将为非空,并采取价值,而不是...