奇怪的struct构造函数编译器解决方法

时间:2015-07-28 22:00:35

标签: c#

结构不能包含显式无参数构造函数。如:

public struct Person
{
    public string Name { get; }
    public int Age { get; }

    public Person(string name = null, int age = 0) { Name = name; Age = age; }
}

然而,这是允许的:

data babies_doctors;
  set babies;
  do _i = 1 to nobs_doctors;
    set doctors point=_i nobs=nobs_doctors;
    array days day1-day6;
    if days[birth_Day] then output;
  end;
run;

任何想法为什么?这有什么不好的理由吗?

4 个答案:

答案 0 :(得分:3)

第二个是允许的,因为它不是无参数的。但是我不会在这里使用可选参数,因为它非常令人困惑 - 如果你调用new Person()你的构造函数将不会被执行(你可以检查它是否替换了默认值除零和零之外):

public struct Person
{
    public string Name { get; }
    public int Age { get; }

    public Person(string name = "Bob", int age = 42)
    {
        Name = name;
        Age = age;
    }
}

因此new Person()default(Person)相同,两者都将使用initobj MSIL指令而不是调用构造函数。

那么,如果你能为结构体定义默认构造函数,为什么会出现问题呢?请考虑以下示例。

private void Test()
{
    Person p1 = new Person(); // ok, this is clear, use ctor if possible, otherwise initobj
    Person p2 = default(Person); // use initobj
    Person p3 = CreateGeneric<Person>(); // and here?
    Person[] persons = new Person[100]; // do we have initialized persons?
}

public T CreateGeneric<T>() where T : new()
{
    return new T();
}

因此,C#中的结构不允许使用真正的无参数构造函数(但在CLR中它受支持)。实际上,无参数构造函数计划在C#6.0中引入;但是,它导致了很多兼容性问题,最终这个功能在最终版本中为removed

答案 1 :(得分:1)

结构的无参数构造函数会使创建considered evil的可变结构更具吸引力。

var person = new Person();
person.Age = 35;
...

我确信还有其他原因,但是一个主要的痛苦是,因为它们被复制,因为它们被传递并且很容易更改错误的结构,因此更容易产生难以诊断的错误。

public void IncreaseAge(Person p)
{
    p += 1; // does not change the original value passed in, only the copy
}

答案 2 :(得分:0)

Any ideas why?

This constructor is not implicitly parameterless -- it has 2 parameters.

Any reason this is bad to do?

Here is a reason: The code can be hard to reason about.

You may expect that if you wrote:

var people = new Person[100];

that all People in that array would have the default values for the optional arguments but this is untrue.

答案 3 :(得分:0)

The values of optional arguments are hardcoded into the calling code.

If later you choose the change your defaults, all compiled code will retain the values it was compiled with.