我们是否应该始终在类中包含默认构造函数?

时间:2010-09-11 18:02:58

标签: c# .net clr default-constructor

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

示例

public class Foo {

    Foo() { }

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

}

我也有兴趣从专家那里了解一下。

8 个答案:

答案 0 :(得分:107)

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

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()
   {
      // ...
   }
}

答案 1 :(得分:19)

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

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

答案 2 :(得分:12)

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

答案 3 :(得分:5)

拥有默认构造函数只是一个好主意,如果有这样的对象是有意义的。

如果从这样的构造函数生成一个不在有效状态的对象,那么它唯一能做的就是引入一个bug。

答案 4 :(得分:1)

是最好有一个默认构造函数,以确保您避免任何混淆。我看到人们只是在默认构造函数中做任何事情(即使在Microsoft自己的类中),但仍然喜欢保持它,因为对象会自动获得默认(类型)。没有指定默认构造函数的类,.NET会自动为你添加它们。

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

在大多数情况下,默认构造函数是个好主意。但是既然你使用“总是”这个词,那么所需要的就是一个反例。如果你看看框架,你会发现很多。例如,System.Web.HttpContext。

答案 7 :(得分:0)

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

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

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