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

Ale*_*lex 210 c# constructor constructor-chaining

我知道这应该是一个非常简单的问题,但我一直在努力解决这个概念.我的问题是,你如何在c#中链接构造函数?我是第一个OOP课程,所以我只是在学习.我不明白构造函数链如何工作或如何实现它,甚至为什么它不仅仅是没有链接的构造函数.

我会很感激一些解释的例子.

那么如何将它们联系起来呢?我知道有两个:

public SomeClass this: {0}

public SomeClass
{
    someVariable = 0
} 
Run Code Online (Sandbox Code Playgroud)

但你如何用三,四等做到这一点?

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

Mar*_*ell 324

您可以使用标准语法(使用this类似的方法)来挑过载,内部类:

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) 
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

Foo a = new Foo(), b = new Foo(456,"def"), c = new Foo(123), d = new Foo("abc");
Run Code Online (Sandbox Code Playgroud)

另请注意:

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

对于"为什么?":

请注意,您也可以以类似的方式使用对象初始值设定项(无需编写任何内容):

SomeType x = new SomeType(), y = new SomeType { Key = "abc" },
         z = new SomeType { DoB = DateTime.Today };
Run Code Online (Sandbox Code Playgroud)


小智 56

我只想向搜索此内容的任何人提出一个有效的观点.如果您打算使用4.0之前的.NET版本(VS2010),请注意您必须创建如上所示的构造函数链.

但是,如果你住在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");
}
Run Code Online (Sandbox Code Playgroud)

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

我希望你喜欢这一课!我无法相信开发人员一直在抱怨构造链接,并且自2004/2005以来无法使用默认的可选参数!现在它已经在开发领域花了很长时间,开发人员害怕使用它,因为它不会向后兼容.

  • 如果使用此技术,则必须注意默认参数是在*caller*的编译时设置的,而不是*callee*.这意味着如果您在库中部署这样的代码,并且应用程序使用带有默认args的构造函数; 如果默认参数发生变化,您需要使用库重新编译应用程序.有些人认为公共接口中的默认参数因为这个问题而具有内在的危险性. (53认同)
  • 默认参数方法的另一个缺点是,例如,如果构造函数中有两个默认参数,则不能仅使用第二个调用它。在这里的例子中,你会编译错误:`Foo myFooOne = new Foo("");` (2认同)

blo*_*art 29

用一个例子可以很好地说明这一点.影像我们有一类人

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;
}
Run Code Online (Sandbox Code Playgroud)

所以这里我们有一个构造函数来设置一些属性,并使用构造函数链接来允许您只使用名称或名称和地址来创建对象.如果您只使用名称创建一个实例,则会将默认值string.Empty发送到名称和地址,然后将Postcode的默认值发送到最终构造函数.

这样做可以减少您编写的代码量.只有一个构造函数实际上有代码,你不是自己重复,所以,例如,如果你将Name从一个属性更改为一个内部字段,你只需要改变一个构造函数 - 如果你在所有三个构造函数中设置了该属性这将是改变它的三个地方.


Jha*_*bub 12

我有一本日记课,所以我不是一次又一次地设定价值观

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;
}
Run Code Online (Sandbox Code Playgroud)


hth*_*tho 9

所有这些答案都很好,但我想在具有更复杂初始化的构造函数上添加注释。

class SomeClass {
    private int StringLength;
    SomeClass(string x) {
         // this is the logic that shall be executed for all constructors.
         // you dont want to duplicate it.
         StringLength = x.Length;
    }
    SomeClass(int a, int b): this(TransformToString(a, b)) {
    }
    private static string TransformToString(int a, int b) {
         var c = a + b;
         return $"{a} + {b} = {c}";
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管这个例子也可以在没有这个静态函数的情况下解决,但静态函数允许更复杂的逻辑,甚至可以从其他地方调用方法。


M.i*_*i.T 8

什么是"构造链"的用法?
您可以使用它从另一个构造函数中调用一个构造函数.

如何实现"构造链"?
在构造函数定义之后使用":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;
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么有用?
重要原因是减少编码,防止重复代码.例如重复初始化属性的代码假设类中的某些属性必须用特定值初始化(在我们的示例中,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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Man*_*ani 6

你在问这个吗?

  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;
    }

}
Run Code Online (Sandbox Code Playgroud)