79

一位同事问我这个问题,我们是否应该始终在类中包含默认构造函数?如果是这样,为什么?如果没有,为什么不呢?

例子

public class Foo {

    Foo() { }

    Foo(int x, int y) {
        ...
    } 

}

我也有兴趣从专家那里得到一些启发。

4

8 回答 8

126

您必须记住,如果您不提供重载的构造函数,编译器将为您生成一个默认构造函数。这意味着,如果你有

public class Foo
{ 
} 

编译器会将其生成为:

public class Foo
{ 
    public Foo() { }  
} 

但是,只要您添加其他构造函数

public class Foo
{ 
    public Foo(int x, int y)
    { 
        // ... 
    }  
} 

编译器将不再为您自动生成默认构造函数。如果该类已经在其他依赖于默认构造函数存在的代码中使用,则Foo f = new Foo();该代码现在将中断。

如果您不希望有人能够在不提供数据的情况下初始化类,您应该创建一个默认构造函数,该构造函数private明确说明您正在防止在没有输入数据的情况下构造实例。

但是,有时需要提供默认构造函数(无论是公共的还是私有的)。如前所述,某些类型的序列化需要默认构造函数。有时一个类有多个参数化构造函数,但也需要“较低级别”的初始化,在这种情况下,可以使用从参数化构造函数链接的私有默认构造函数。

public class Foo
{
   private Foo()
   {
      // do some low level initialization here
   }

   public Foo(int x, int y)
      : this()
   {
      // ...
   }

   public Foo(int x, int y, int z)
      : this()
   {
      // ...
   }
}
于 2010-09-11T18:12:53.017 回答
20

有些事情(比如序列化)需要一个默认的构造函数。但是,除此之外,只有在有意义的情况下才应添加默认构造函数。

例如,如果Foo.XandFoo.Y属性在构造后是不可变的,那么默认构造函数就没有意义了。即使它用于“空”Foo,静态Empty访问器也更容易被发现。

于 2010-09-11T18:06:24.417 回答
12

我会说不绝对不会总是这样。假设您有一个包含一些只读字段的类,这些字段必须初始化为某个值,并且没有合理的默认值(或者您不希望有)?在这种情况下,我认为无参数构造函数没有意义。

于 2010-09-11T18:07:52.557 回答
6

只有当拥有这样一个对象有意义时,拥有一个默认构造函数才是一个好主意。

如果你从这样的构造函数中生成了一个不处于有效状态的对象,那么它唯一能做的就是引入一个错误。

于 2010-09-11T22:18:54.493 回答
2

作为旁注,当使用 struct 而不是 class 时,请注意,没有办法将默认构造函数排除在外,也不可能自己定义它,因此无论您定义哪些构造函数,请确保struct(当所有变量都设置为默认状态时(通常为值类型为 0,引用类型为 null)不会破坏结构的实现。

于 2010-09-12T05:58:09.930 回答
1

是的 最好有一个默认构造函数,以确保避免任何混淆。我见过人们在默认构造函数中什么都不做(即使在微软自己的类中),但仍然喜欢保留它,因为对象会自动获取默认值(类型)。没有指定默认构造函数的类,.NET 会自动为你添加。

如果您使用现有的序列化程序,则序列化需要默认构造函数,因为它对通用序列化程序有意义,否则您需要创建自己的实现。

于 2010-09-11T20:35:09.277 回答
0

在大多数情况下,默认构造函数是个好主意。但是由于您使用“始终”一词,因此只需要一个反例即可。如果您查看框架,您会发现很多。例如,System.Web.HttpContext。

于 2010-09-11T18:10:14.767 回答
0

如果泛型类型具有默认构造函数,则只能使用 C# 方法(无需反射)对其进行实例化。此外,new()必须指定泛型类型约束:

void Construct<T>()
    where T : new()
{
    var t = new T();
    ...
}

使用没有默认构造函数的类型作为泛型类型参数调用此方法会导致编译器错误。

于 2016-03-10T19:05:57.610 回答