C#构造函数链? (怎么做?)

我知道这应该是一个超级简单的问题,但我一直在为这个概念挣扎。 我的问题是,你如何链接在C#构造函数? 我在我的第一个OOPclass,所以我只是在学习。 我不明白构造函数链如何工作或如何实现它,甚至为什么比没有链的构造函数更好。

我会感谢一些例子的解释。

那么如何链接他们呢? 我知道两个它是:

public SomeClass this: {0} public SomeClass { someVariable = 0 } 

但是你怎么用三,四等等呢?

再次,我知道这是一个初学者的问题,但我很难理解这一点,我不知道为什么。

你使用标准的语法(使用this方法)来select类中的重载:

 class Foo { private int id; private string name; public Foo() : this(0, "") { } public Foo(int id, string name) { this.id = id; this.name = name; } public Foo(int id) : this(id, "") { } public Foo(string name) : this(0, name) { } } 

然后:

 Foo a = new Foo(), b = new Foo(456,"def"), c = new Foo(123), d = new Foo("abc"); 

还要注意:

  • 你可以链接到基类的构造函数使用base(...)
  • 你可以在每个构造函数中join额外的代码
  • 默认(如果你没有指定任何东西)是base()

为什么?

  • 代码减less(总是一件好事)
  • 有必要调用一个非默认的基础构造函数,例如:

     SomeBaseType(int id) : base(id) {...} 

注意,你也可以用类似的方式使用对象初始值设定项,尽pipe(不需要写任何东西):

 SomeType x = new SomeType(), y = new SomeType { Key = "abc" }, z = new SomeType { DoB = DateTime.Today }; 

我只想提出一个有效的观点给任何人寻找这个。 如果你打算使用.NET 4.0以前的版本(VS2010),请注意,你必须创build如上所示的构造函数链。

但是,如果你留在4.0,我有好消息。 你现在可以有一个可选参数的构造函数! 我将简化Foo类的例子:

 class Foo { private int id; private string name; public Foo(int id = 0, string name = "") { this.id = id; this.name = name; } } class Main() { // Foo Int: Foo myFooOne = new Foo(12); // Foo String: Foo myFooTwo = new Foo(name:"Timothy"); // Foo Both: Foo myFooThree = new Foo(13, name:"Monkey"); } 

在实现构造函数时,可以使用可选参数,因为已经设置了默认值。

我希望你喜欢这节课! 我不敢相信开发者自2004/05年以来一直在抱怨构造链,不能使用默认的可选参数! 现在在开发世界已经花了很长时间,开发人员害怕使用它,因为它不会向后兼容。

举一个例子来说明这一点。 成像我们有一个class人

 public Person(string name) : this(name, string.Empty) { } public Person(string name, string address) : this(name, address, string.Empty) { } public Person(string name, string address, string postcode) { this.Name = name; this.Address = address; this.Postcode = postcode; } 

所以在这里我们有一个构造函数,它设置了一些属性,并使用构造函数链来让你创build一个只有名字的对象,或者只是一个名字和地址。 如果你用一个名字创build一个实例,它将发送一个默认值string.Empty到name和address,然后发送Postcode的默认值到最终的构造函数。

这样做可以减less你写的代码量。 只有一个构造函数实际上有代码,你不重复自己,所以,例如,如果你将一个属性的Name改成一个内部的字段,你只需要改变一个构造函数 – 如果你在这三个构造函数中设置了这个属性那将是三个地方去改变它。

我有一个日记课,所以我不写一次又一次地设置值

 public Diary() { this.Like = defaultLike; this.Dislike = defaultDislike; } public Diary(string title, string diary): this() { this.Title = title; this.DiaryText = diary; } public Diary(string title, string diary, string category): this(title, diary) { this.Category = category; } public Diary(int id, string title, string diary, string category) : this(title, diary, category) { this.DiaryID = id; } 

你问这个吗?

  public class VariantDate { public int day; public int month; public int year; public VariantDate(int day) : this(day, 1) {} public VariantDate(int day, int month) : this(day, month,1900){} public VariantDate(int day, int month, int year){ this.day=day; this.month=month; this.year=year; } } 

我希望下面的例子对构造函数链进行了一些阐述。
我的用例在这里,例如,你期待用户传递一个目录到你的构造函数,用户不知道什么目录通过,并决定让你指定默认目录。 你加强,并分配一个你认为会工作的默认目录。

顺便说一句,我用LINQPad这个例子,如果你想知道* .Dump()是什么。
干杯

 void Main() { CtorChaining ctorNoparam = new CtorChaining(); ctorNoparam.Dump(); //Result --> BaseDir C:\Program Files (x86)\Default\ CtorChaining ctorOneparam = new CtorChaining("c:\\customDir"); ctorOneparam.Dump(); //Result --> BaseDir c:\customDir } public class CtorChaining { public string BaseDir; public static string DefaultDir = @"C:\Program Files (x86)\Default\"; public CtorChaining(): this(null) {} public CtorChaining(string baseDir): this(baseDir, DefaultDir){} public CtorChaining(string baseDir, string defaultDir) { //if baseDir == null, this.BaseDir = @"C:\Program Files (x86)\Default\" this.BaseDir = baseDir ?? defaultDir; } } 

构造函数链中还有一个重点:顺序。 为什么? 假设您有一个对象在运行时被一个框架构造,该框架期望它是默认的构造器。 如果你想在传递值的时候仍然有能力在你想要的时候传递构造函数的话,这是非常有用的。

我可以例如有一个支持variables被默认的构造函数设置为默认值,但有能力被覆盖。

 public class MyClass { private IDependency _myDependency; MyClass(){ _myDependency = new DefaultDependency(); } MYClass(IMyDependency dependency) : this() { _myDependency = dependency; //now our dependency object replaces the defaultDependency } } 

什么是“构造链”的用法?
您使用它从另一个构造函数调用一个构造函数。

如何实现“构造器链”?
构造函数的定义之后使用“:this(yourProperties)”关键字。 例如:

 Class MyBillClass { private DateTime requestDate; private int requestCount; public MyBillClass() { /// ===== we naming "a" constructor ===== /// requestDate = DateTime.Now; } public MyBillClass(int inputCount) : this() { /// ===== we naming "b" constructor ===== /// /// ===== This method is "Chained Method" ===== /// this.requestCount= inputCount; } } 

为什么它有用?
重要的原因是减less编码,并防止重复的代码。 例如重复初始化属性的代码假设类中的某些属性必须使用特定的值进行初始化(在我们的示例requestDate中)。 而类有2个或更多的构造函数。 如果没有“构造器链”,则必须在所有类的构造器中重复初始化代码。

它是如何工作的? (或者,“构造器链”中的执行顺序是什么)?
在上例中,首先执行方法“a”,然后指令序列返回方法“b”。 换句话说,上面的代码等于下面的代码:

 Class MyBillClass { private DateTime requestDate; private int requestCount; public MyBillClass() { /// ===== we naming "a" constructor ===== /// requestDate = DateTime.Now; } public MyBillClass(int inputCount) : this() { /// ===== we naming "b" constructor ===== /// // ===== This method is "Chained Method" ===== /// /// *** --- > Compiler execute "MyBillClass()" first, And then continue instruction sequence from here this.requestCount= inputCount; } }