使用默认参数调用构造函数而不是默认构造函数

6

我想调用一个结构体的构造函数,该构造函数对所有参数都有默认值。但当我调用MyRectangle的无参构造函数时,会调用一个未定义的构造函数。为什么会这样?有没有不调用由我创建的构造函数的方法?

using System;

namespace UebungClasses
{
    class Program
    {
        static void Main(string[] args)
        {
            MyRectangle sixRec = new MyRectangle(3, 2);
            MyRectangle oneRec = new MyRectangle();

            Console.WriteLine("area of six: " + sixRec.Area() + " area of one: " + oneRec.Area());
        }
    }

    public struct MyRectangle
    { 
        public MyRectangle(double w = 1, double l = 1)
        {
            width = w;
            length = l;
            Console.WriteLine("Width: " + width + " Lenght: " + length);
        }

        public double Area()
        {
            return width * length;
        }

        private double width;
        private double length;
    }
}

如果 MyRectangle 是一个 class 而不是 struct,它将按照您的意图工作。但由于历史原因,任何使用 new T() 其中 T 是值类型,都与 default(T) 相同。 - Jeppe Stig Nielsen
你尝试过将无参构造函数声明为私有的吗,例如「private MyRectangle() {}」? - santamanno
2个回答

5
不会的,如果您使用 new MyRectangle() ,它将始终优先选择默认构造函数(意味着在 struct 的情况下为零)。
如果您正在处理整数,则一个潜在的解决方法是在属性访问器中使用异或运算符与所需的默认值 - 这意味着当字段为零时,您可以从访问器获取默认值。不幸的是,要在 double 中执行此操作需要使用不安全代码重新解释类型。
另一个可能的解决方案是添加一个您可以使用的虚拟参数,例如:
new MyRectangle(dummy: true)

这个dummy参数实际上除了允许你选择自定义构造函数之外,什么也不会做。

另一个最终的选择是使用工厂方法(static MyRectangle Create(...))代替构造函数。


你不认为“isNotDefault”标记是一个可行的选择吗?你会在访问任何属性时付出一些小的代价,但如果这不是问题的话,这是一种相当干净的方法来获得结构体中定制的“默认”值行为。 - InBetween
我同意,我指的是一般情况,其中不涉及整数。 - InBetween
有点遗憾,我不能按照自己想要的方式完成那件事,但是嘿,至少我学到了新的东西!谢谢。 - InfoMathze
不必使用XOR,您可以减去“1.0”。例如:public MyRectangle(double w = 1.0, double l = 1.0) { widthMinusOne = w - 1.0; lengthMinusOne = l - 1.0; } 每次读取字段时(可以为此添加属性),您需要再次添加“1.0”,例如在“Area”方法中。 - Jeppe Stig Nielsen
@JeppeStigNielsen 或许是这样,但异或运算比算术运算更便宜——特别是浮点数算术运算;此外,在浮点数情况下,由于四舍五入的原因(尤其是如果触发了比例变化),有可能会影响值,而异或则保证不会产生副作用。 - Marc Gravell
显示剩余4条评论

1
这里的问题在于编译器总是优先选择没有默认参数的有效构造函数。这有点像泛型,非泛型重载会胜出,这里也是,非默认参数重载更受青睐。
由于结构体都有一个无参构造函数,所以编译器会选择它,而不是你自己定义的构造函数。
如果需要不同的默认矩形,可以通过以下方式解决:
public struct MyRectangle
{
    private readonly bool isNotDefault;

    public MyRectangle(double w, double l)
    {
        isNotDefault = true;
        width = w;
        length = l;
    }

    public double Area()
    {
        //Notice the use of the properties,
        //not the backing fields.
        return Width * Length;             
    }

    private readonly double width, length;
    public double Width => isNotDefault ? width: 1;
    public double Length => isNotDefault ? length : 1;

    public override string ToString()
        => $"Width: {Width} Lenght: {Length}";
}

我不确定是否建议在矩形中使用这个方法,因为零大小的矩形似乎是一个合理的选择,但有些情况下默认值确实没有意义。一个明显的例子是表示有理数的结构体,其中默认值是数学上的不确定性:0/0


是的,当然默认值为0/0更合适,但我想试着“精简代码”如SE所建议的。谢谢您的回答,但我认为我会接受另一个回答。 - InfoMathze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接