2012-07-02 56 views
27

C# 4 giới thiệu một tính năng gọi là named arguments đó là đặc biệt hữu ích trong các tình huống nhưBuộc tên đối số trong C#

int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email) 

Có cách nào để buộc sử dụng đối số được đặt tên? Có lẽ một số thuộc tính để áp dụng cho một phương pháp hoặc chuyển đổi một trình biên dịch tôi không biết? Tôi đoán nó có thể được thực hiện với các công cụ kiểm tra mã nhưng chỉ muốn biết nếu có cách khác.

p.s.

Đối với những người quan tâm lý do tại sao người ta có thể cần nó và tại sao không chỉ sử dụng một lớp/struct để sử dụng object initializers có những trường hợp khi nó không thể. Giống như các cuộc gọi đến các thư viện không nằm trong kiểm soát của bạn hoặc các quy ước mã lạ bạn phải tuân thủ.

+4

Tôi không thấy sử dụng nhiều trong args tên trừ khi args của bạn chủ yếu là bắt buộc. –

+1

@BobKaufman Tôi đoán ngược lại. Khi bạn biên dịch mã, nó "quên" cho dù nó được gọi là tham số vị trí, được đặt tên hoặc giá trị mặc định. –

+1

Tại sao bạn cần điều này? Nó có phải là một quy ước mã được áp đặt lên bạn? – driis

Trả lời

24

Không, không phải bằng ngôn ngữ C#. Nó sẽ luôn luôn chấp nhận các tham số vị trí nếu tất cả các tham số được cung cấp.

Bạn có thể build a custom FxCop rule hoặc StyleCop rule để thực thi điều này - như được nêu trong các nhận xét, đó có thể là quy tắc StyleCop bạn sẽ quan tâm (nhờ Kris).

+7

Bạn không thể thực hiện quy tắc FxCop tùy chỉnh, vì quy tắc FxCop hoạt động trên các tệp nhị phân, không phải nguồn và các đối số được đặt tên là "được biên dịch". Tôi cho rằng bạn có thể tạo một quy tắc StyleCop tùy chỉnh. –

+0

@KrisVandermotten, tôi nghĩ rằng bạn là đúng, tuy nhiên FxCop có thể trích xuất thông tin từ PDB, nhưng tôi không biết nếu việc sử dụng các tham số được đặt tên đi vào PDB. Nếu đó không phải là trường hợp, tôi đoán một quy tắc cảnh sát phong cách là cần thiết để thay thế. – driis

+2

Không, đối với các tham số có tên là PDB: "máy tính nói không!". –

15

Có thể buộc người gọi phải luôn sử dụng tên là args. Tôi sẽ không làm điều này trong hầu hết các trường hợp bởi vì nó khá xấu xí, nhưng nó phụ thuộc vào cách sử dụng phương pháp kém an toàn là cần thiết.

Dưới đây là giải pháp:

int RegisterUser(
#if DEBUG 
     int _ = 0, 
#endif 
     string nameFirst = null, 
     string nameLast = null, 
     string nameMiddle = null, 
     string email = null) { /*...*/ } 

Tham số đầu tiên là một hình nộm không nên được sử dụng (và được biên dịch ra trong phiên bản lần cho hiệu quả). Tuy nhiên, nó đảm bảo rằng tất cả các thông số sau phải được đặt tên.

sử dụng hợp lệ là bất kỳ sự kết hợp của các thông số được đặt tên:

RegisterUser(); 
    RegisterUser(nameFirst: "Joe"); 
    RegisterUser(nameFirst: "Joe", nameLast: "Smith"); 
    RegisterUser(email: "[email protected]"); 

Khi cố gắng để sử dụng tham số vị trí, mã sẽ không biên dịch.

+2

Với chỉ thị tiền xử lý biên dịch của bạn, nó hoạt động như thể 'int _ = 0' thậm chí không tồn tại nếu biểu tượng DEBUG không được xác định, vì vậy nó không có bất kỳ tác dụng nào cho bản phát hành ... I don ' t nghĩ rằng câu trả lời này làm những gì bạn nghĩ rằng nó ... – Zack

+2

Hiệu ứng là tham số "_" không sử dụng với giá trị mặc định buộc các tham số còn lại có giá trị mặc định và được đặt tên khi gọi. – user4698855

+5

Xấu xí, nhưng thông minh. – joelsand

2

Tôi cũng đã tìm cách ép buộc các đối số được đặt tên. Các tham số tùy chọn có thể nguy hiểm, đặc biệt nếu bạn có nhiều tham số cùng loại. Quá tải luôn luôn là một giải pháp an toàn hơn, nhưng có những lúc bạn có một phương pháp có thể mất nhiều kết hợp các đối số, do đó, việc tạo ra 20 tình trạng quá tải cho tài khoản cho khả năng bao giờ là quá mức cần thiết.

Trong trường hợp cực kỳ quan trọng nhất mà đối số được đặt tên mọi lúc, tôi sẽ tạo một lớp đối số không có hàm tạo được xác định. Trong trường hợp của bạn, bạn có thể làm điều này:

public class UserRegistrationArguments 
{ 
    public string nameFirst { get; set; } 
    public string nameLast { get; set; } 
    public string nameMiddle { get; set; } 
    public string email { get; set; } 
} 

Gọi nó như thế này:

RegisterUser(new UserRegistrationArguments { nameFirst = "Bob", nameLast = "Slob" }); 

Bạn cũng có thể đơn giản hóa nó như thế này:

public class UserRegistrationArguments 
{ 
    public string nameMiddle { get; set; } 
    public string email { get; set; } 
} 

int RegisterUser(string nameFirst, string nameLast, UserRegistrationArguments args = null) 

... và làm như sau:

RegisterUser("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" }); 

Bằng cách này, bạn chỉ có một tham số tùy chọn er và đó là thông số tùy chọn của bạn.

Chỉnh sửa: Có lẽ tôi không đọc chính xác OP. Bạn không sử dụng các đối số tùy chọn? Nếu không thì câu trả lời này có lẽ không giúp bạn.

0

Tôi đang sử dụng một phương pháp khác. Trong thiết lập của tôi, tôi có 1 tham số mà tôi luôn mong đợi, sau đó đến một loạt các chuỗi tùy chọn mà tôi thực sự muốn chắc chắn rằng người dùng đã chọn chủ động. Vì vậy, chuỗi đầu tiên của tôi trong danh sách này là một giá trị "bẫy", nếu được đặt, sẽ phát ra lỗi. Như thế này:

public HtmlString Toolbar(DynamicEntity target = null, string dontRelyOnParameterOrder = Constants.RandomProtectionParameter, string actions = null, string contentType = null, object prefill = null) 
    { 
     if (!Enabled) return null; 
     protectAgainstMissingParameterNames(dontRelyOnParameterOrder); 

     var toolbar = new ItemToolbar(target, actions, contentType, prefill); 

     return new HtmlString(toolbar.Toolbar); 
    } 

    private void protectAgainstMissingParameterNames(string criticalParameter) 
    { 
     if(criticalParameter != Constants.RandomProtectionParameter) 
      throw new Exception("when using the toolbar command, please use named parameters - otherwise you are relying on the parameter order staying the same."); 

    } 

Hy vọng bạn thích nó :)

Các vấn đề liên quan