2009-11-29 5 views
182

Tôi biết rằng đây được cho là một câu hỏi cực kỳ đơn giản, nhưng tôi đã đấu tranh với khái niệm này một thời gian. Câu hỏi của tôi là, làm thế nào để bạn xây dựng chuỗi trong C#? Tôi đang ở trong lớp OOP đầu tiên của mình, vì vậy tôi chỉ đang học. Tôi không hiểu làm thế nào để xây dựng chuỗi hoạt động hoặc làm thế nào để thực hiện nó, hoặc thậm chí lý do tại sao nó tốt hơn so với chỉ làm nhà thầu mà không có chuỗi.C# constructor chaining? (Làm thế nào để làm điều đó?)

Tôi sẽ đánh giá cao một số ví dụ với giải thích.

Vậy làm thế nào để chuỗi chúng? Tôi biết với hai điều này:

public SomeClass this: {0} 

public SomeClass 
{ 
    someVariable = 0 
} 

Nhưng làm cách nào bạn làm điều đó với ba, bốn v.v ...?

Một lần nữa, tôi biết đây là câu hỏi mới bắt đầu, nhưng tôi đang cố gắng để hiểu điều này và tôi không biết tại sao.

Trả lời

275

Bạn sử dụng cú pháp tiêu chuẩn (sử dụng this như một phương pháp) để chọn quá tải, bên lớp:

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) { 
    } 
} 

thì:

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

Cũng lưu ý:

  • bạn có thể kết nối với các nhà thầu trên cơ sở loại sử dụng base(...)
  • bạn có thể đặt thêm mã vào mỗi constructor
  • mặc định (nếu bạn không chỉ định bất cứ điều gì) là base()

Đối với "tại sao?":

giảm đang
  • (luôn luôn một điều tốt)
  • cần thiết để gọi hàm tạo cơ sở không mặc định, ví dụ:

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

Lưu ý rằng bạn cũng có thể sử dụng initializers đối tượng trong một cách tương tự, mặc dù (mà không cần phải viết bất cứ điều gì):

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

Tôi đang làm một số chuỗi và phải đặt câu hỏi vì câu trả lời này đã được bình chọn rất cao. Có bất kỳ bất lợi để có mỗi nhà xây dựng thiết lập các thuộc tính đã được truyền cho nó, và sau đó gọi constructor mặc định để thiết lập những người khác? Bằng cách này, bạn không mã hóa các giá trị mặc định ('0' và' "" ') ở nhiều nơi (ít cơ hội hơn cho một lỗi). Ví dụ: 'public Foo (int id): this() {this.id = id; } '? Ngoài ra, tôi cũng đang xem xét: 'public Foo (int id): this (" ") {this.id = id; } '. Chỉ cần tìm cách hợp lý nhất để kết nối chúng, đánh giá cao bất kỳ suy nghĩ nào. –

+0

Có cách nào để thao tác các giá trị đối số của hàm được gọi là hàm tạo trong hàm tạo đầu tiên trước khi hàm tạo khác được gọi không? – eaglei22

5

Bạn có yêu cầu về điều này?

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

} 
25

Điều này được minh họa tốt nhất với ví dụ. Imaging chúng tôi có một Person lớp

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

Vì vậy, ở đây chúng tôi có một constructor mà đặt ra một số tài sản, và sử dụng constructor chaining để cho phép bạn tạo ra các đối tượng chỉ với một cái tên, hay chỉ là một tên và địa chỉ. Nếu bạn tạo một cá thể chỉ với một tên, điều này sẽ gửi một giá trị mặc định, string.Empty đến tên và địa chỉ, sau đó gửi một giá trị mặc định cho Mã bưu điện đến cho hàm tạo cuối cùng.

Khi làm như vậy, bạn sẽ giảm số lượng mã bạn đã viết.Chỉ có một hàm tạo thực sự có mã trong nó, bạn không lặp lại chính mình, ví dụ, nếu bạn đổi Tên từ một thuộc tính thành một trường nội bộ, bạn chỉ cần thay đổi một hàm khởi tạo - nếu bạn đặt thuộc tính đó trong cả ba hàm tạo đó sẽ là ba nơi để thay đổi nó.

54

Tôi chỉ muốn đưa ra một điểm hợp lệ cho bất kỳ ai tìm kiếm điều này. Nếu bạn định làm việc với các phiên bản .NET trước 4.0 (VS2010), xin lưu ý rằng bạn phải tạo các chuỗi hàm dựng như được hiển thị ở trên.

Tuy nhiên, nếu bạn ở trong 4.0, tôi có tin vui. Bây giờ bạn có thể có một hàm tạo duy nhất với các đối số tùy chọn! Tôi sẽ đơn giản hóa ví dụ về lớp 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"); 
} 

Khi bạn triển khai hàm tạo, bạn có thể sử dụng các đối số tùy chọn vì mặc định đã được đặt.

Tôi hy vọng bạn thích bài học này! Tôi không thể tin rằng các nhà phát triển đã phàn nàn về việc xây dựng chuỗi và không thể sử dụng các đối số tùy chọn mặc định kể từ 2004/2005! Bây giờ nó đã lấy SO lâu trong thế giới phát triển, các nhà phát triển sợ sử dụng nó bởi vì nó sẽ không tương thích ngược.

+46

Nếu bạn sử dụng kỹ thuật này, bạn phải lưu ý rằng các đối số mặc định được đặt tại thời gian biên dịch trong * người gọi *, không phải là * callee *. Điều đó có nghĩa là nếu bạn triển khai mã như thế này trong một thư viện và một ứng dụng sử dụng một hàm tạo với các tham số mặc định; bạn cần biên dịch lại ứng dụng bằng thư viện nếu các đối số mặc định thay đổi. Một số người xem xét các đối số mặc định trong các giao diện công cộng vốn đã nguy hiểm do lỗi này. – Chuu

+1

Một hạn chế khác với cách tiếp cận đối số mặc định là nếu bạn có ví dụ hai mặc định args trong hàm tạo, bạn không thể gọi nó chỉ bằng phương thức thứ hai. Trong ví dụ ở đây, bạn sẽ phải biên dịch lỗi cho: 'Foo myFooOne = new Foo (" ");' –

9

Tôi có một lớp nhật ký và do đó tôi không thiết lập các giá trị văn bản một lần nữa và một lần nữa

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

Tôi hy vọng theo gương sáng tỏ một số nhà xây dựng loạt. Ví dụ:
trường hợp sử dụng của tôi ở đây, bạn đang mong đợi người dùng chuyển một thư mục đến nhà xây dựng của bạn, người dùng không biết thư mục nào cần chuyển và quyết định để gán thư mục mặc định. bạn bước lên và gán một thư mục mặc định mà bạn nghĩ rằng sẽ hoạt động.

BTW, tôi đã sử dụng LINQPad cho ví dụ này trong trường hợp bạn đang tự hỏi những gì * .Dump() là.
cổ vũ

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

Có một điểm quan trọng trong việc xây dựng chaining: trật tự. Tại sao? Giả sử bạn có một đối tượng đang được xây dựng trong thời gian chạy theo một khung công tác dự kiến ​​đó là hàm tạo mặc định. Nếu bạn muốn có thể truyền các giá trị trong khi vẫn có khả năng truyền trong các hàm tạo của nhà xây dựng khi bạn muốn, điều này cực kỳ hữu ích.

Ví dụ: tôi có thể có biến số sao lưu được đặt thành giá trị mặc định bởi hàm tạo mặc định của tôi nhưng có khả năng bị ghi đè.

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

Cách sử dụng "Chuỗi xây dựng" là gì?
Bạn sử dụng nó để gọi một hàm tạo từ một hàm tạo khác.

Làm cách nào để triển khai "Chuỗi xây dựng"?
Sử dụng từ khóa ": this (yourProperties)" sau định nghĩa của hàm tạo. ví dụ:

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

Tại sao lại hữu ích?
Lý do quan trọng là giảm mã hóa và ngăn chặn mã trùng lặp.chẳng hạn như mã lặp lại để khởi tạo thuộc tính Giả sử một số thuộc tính trong lớp phải được khởi tạo với giá trị cụ thể (Trong mẫu của chúng tôi, requestDate). Và lớp có 2 hoặc nhiều hàm tạo. Không có "Constructor Chain", bạn phải lặp lại mã khởi tạo trong tất cả các phần tử con của lớp.

Cách hoạt động? (Hoặc, Chuỗi thực hiện trong chuỗi "Constructor") là gì?
trong ví dụ trên, phương thức "a" sẽ được thực thi trước, sau đó trình tự lệnh sẽ trở về phương thức "b". Nói cách khác, mã trên bằng với dưới đây:

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