2009-07-21 9 views
5

Vì vậy, tôi có một lớp với một tham số chuỗi duy nhất trong constructor của nó là gì:cách chính xác để xác nhận các đối số của một constructor

public MyClass(string name) 
{ 
    this.Name = name; 
} 

nhưng tôi không bao giờ muốn phải lo lắng về một số một khởi tạo một thể hiện của MyClass với tên là NULL hoặc chuỗi có độ dài bằng không. Cách tốt nhất để xác thực tham số là gì? Với một thuộc tính hoặc phương thức bạn luôn có thể không làm gì cả, trả về null hoặc không đặt bất cứ điều gì nếu một đối số không hợp lệ được cung cấp. Nhưng một khi một constructor được gọi là instance của đối tượng đã được tạo ra bất kể nó đã được thông qua các đối số hợp lệ chưa.

Có phải ném một ngoại lệ như được hiển thị bên dưới theo cách tốt nhất không? Hay có phương pháp nào khác được ưa thích hơn?

public MyClass(string name) 
{ 
    if (name == null | name == "") throw new ArgumentException("Name can not be null or blank", "name"); 

    this.Name = name; 
} 

Tất nhiên tôi luôn luôn có thể thiết lập tên cho một số mặc định như "MyClass Không được đặt tên" nếu đối số là không hợp lệ, nhưng trong trường hợp này tôi chỉ muốn ngăn chặn một tên không hợp lệ sau đó cố gắng để giả định một số hành vi thay thế.

Trả lời

7
  1. Ném một Document ArgumentNullException
  2. rằng ctor ném ArgumentNullException nếu tênnull
  3. Nếu bạn đang sử dụng Code Contracts, thêm một dòng Contract.EndContractBlock() sau khi xác nhận thông số của bạn.

Chỉnh sửa: Thay vì điều này:

if (name == null || name == "") 

Sử dụng này:

if (string.IsNullOrEmpty(name)) 
+0

Hãy rất cẩn thận khi ném ngoại lệ trong nhà xây dựng Bạn có thể kết thúc với nguồn lực bị rò rỉ nếu yo bạn đã bắt đầu lấy tài nguyên/phân bổ bộ nhớ, v.v. – Matt

+0

Dù bằng cách nào, nó sẽ không được || (Logic OR) và không | (Bitwise OR)? Chỉ cần tự hỏi. –

+0

@Blaenk, vâng, tôi đã sử dụng sao chép và dán. Ngạc nhiên khi sử dụng của tôi không bị ảnh hưởng bởi lỗi của OP. :) –

1

Bạn có thể đặt tên thành một số mặc định hoặc ném ngoại lệ. Bất cứ điều gì khác chỉ đơn giản là sai vì nó sẽ tạo ra một đối tượng với một trạng thái không hợp lệ.

1

Nếu đi qua một cái tên trống hoặc null thể hiện một lỗi, ném một ngoại lệ là điều hợp lý để làm. Bỏ qua tên null và thực hiện khôi phục tùy ý chỉ là che giấu lỗi và có khả năng dẫn đến trạng thái không hợp lệ.

Nếu không chuyển tên là một cách hợp lệ để xây dựng đối tượng, hãy cung cấp hàm tạo không tham số.

3

Giải pháp ưu tiên ở đây là để ném ngoại lệ. Thất bại sớm, thất bại thường xuyên. Ghi lại các tham số hợp lệ cho constructor của bạn và nó đưa ra một thông số không hợp lệ là ArgumentNullException hoặc ArgumentOutOfRangeException.

Theo tôi, điểm nổi bật là bạn không muốn âm thầm hấp thụ các lỗi. Giả sử người dùng gõ vào một tên không chính xác (ví dụ, vô tình để lại nó null). Tốt hơn để có các hoạt động thất bại và trả lại thông báo cho người dùng hơn là nuốt sự thất bại (với, nói, một mặc định) và có người dùng không biết họ đã nhập sai mục nhập của họ.

Tôi đã yêu cầu question tương tự trở lại để giải quyết tranh cãi với một số đồng nghiệp.

"Nhưng khi một nhà xây dựng được gọi là cá thể của đối tượng đã được tạo bất kể nó có được thông qua các đối số hợp lệ hay không."

Đối tượng được tạo ra (ví dụ, không null) chỉ khi các nhà xây dựng trả về bình thường.

1

Có một lớp tiện ích Guard mà bạn có thể tìm thấy hữu ích cho việc chứng thực đối số truyền cho phương pháp bất kỳ.

lớp là avaialable here using System; sử dụng System.Globalization;.

namespace Microsoft.Practices.Mobile.CompositeUI.Utility 
    { 
     /// <summary> 
     /// Common guard clauses. 
     /// </summary> 
     public static class Guard 
     { 


    /// <summary> 
     /// Checks a string argument to ensure it isn't null or empty. 
     /// </summary> 
     /// <param name="argumentValue">The argument value to check.</param> 
     /// <param name="argumentName">The name of the argument.</param> 
     public static void ArgumentNotNullOrEmptyString(string argumentValue, string argumentName) 
     { 
      ArgumentNotNull(argumentValue, argumentName); 

      if (argumentValue.Trim().Length == 0) 
       throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Properties.Resources.StringCannotBeEmpty, argumentName)); 
     } 

     /// <summary> 
     /// Checks an argument to ensure it isn't null. 
     /// </summary> 
     /// <param name="argumentValue">The argument value to check.</param> 
     /// <param name="argumentName">The name of the argument.</param> 
     public static void ArgumentNotNull(object argumentValue, string argumentName) 
     { 
      if (argumentValue == null) 
       throw new ArgumentNullException(argumentName); 
     } 

     /// <summary> 
     /// Checks an Enum argument to ensure that its value is defined by the specified Enum type. 
     /// </summary> 
     /// <param name="enumType">The Enum type the value should correspond to.</param> 
     /// <param name="value">The value to check for.</param> 
     /// <param name="argumentName">The name of the argument holding the value.</param> 
     public static void EnumValueIsDefined(Type enumType, object value, string argumentName) 
     { 
      if (Enum.IsDefined(enumType, value) == false) 
       throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, 
        Properties.Resources.InvalidEnumValue, 
        argumentName, enumType.ToString())); 
     } 

     /// <summary> 
     /// Verifies that an argument type is assignable from the provided type (meaning 
     /// interfaces are implemented, or classes exist in the base class hierarchy). 
     /// </summary> 
     /// <param name="assignee">The argument type.</param> 
     /// <param name="providedType">The type it must be assignable from.</param> 
     /// <param name="argumentName">The argument name.</param> 
     public static void TypeIsAssignableFromType(Type assignee, Type providedType, string argumentName) 
     { 
      if (!providedType.IsAssignableFrom(assignee)) 
       throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, 
        Properties.Resources.TypeNotCompatible, assignee, providedType), argumentName); 
     } 
    } 
}