2011-07-12 32 views
8

Tôi có một lớp với nhiều trường đại diện cho các giá trị vật lý khác nhau.Cách thanh lịch để xác thực giá trị

class Tunnel 
{ 
    private double _length; 
    private double _crossSectionArea; 
    private double _airDensity; 
    //... 

Mỗi trường được hiển thị bằng thuộc tính đọc/ghi. Tôi cần phải kiểm tra trên setter rằng giá trị là chính xác và tạo ra ngoại lệ khác. Tất cả các xác thực là tương tự:

public double Length 
    { 
     get { return _length; } 
     set 
     { 
      if (value <= 0) throw new ArgumentOutOfRangeException("value", 
        "Length must be positive value."); 
      _length = value; 
     } 
    } 

    public double CrossSectionArea 
    { 
     get { return _crossSectionArea; } 
     set 
     { 
      if (value <= 0) throw new ArgumentOutOfRangeException("value", 
        "Cross-section area must be positive value."); 
      _crossSectionArea = value; 
     } 
    } 

    public double AirDensity 
    { 
     get { return _airDensity; } 
     set 
     { 
      if (value < 0) throw new ArgumentOutOfRangeException("value", 
        "Air density can't be negative value."); 
      _airDensity = value; 
     } 
    } 
    //... 

Có cách nào thanh lịch và linh hoạt để thực hiện việc xác thực như vậy không?

+0

Tôi nghĩ rằng cách bạn đã thực hiện nó là con đường đúng để đi. Thay đổi duy nhất có thể là tạo một 'hàm validator' mà bạn gọi bất cứ khi nào bạn sẵn sàng kiểm tra * tất cả * các giá trị của bạn cùng một lúc. Theo kinh nghiệm của tôi, Visual Studio (không biết những gì bạn đang sử dụng) dường như nuốt các ngoại lệ xảy ra trong một setter tài sản. – jp2code

+0

@ jp2code, ngoại lệ trong setter hoạt động tốt. Mới kiểm tra. –

Trả lời

6

Giả sử bạn muốn loại hành vi này, bạn có thể xem xét một số phương pháp helper, ví dụ

public static double ValidatePositive(double input, string name) 
{ 
    if (input <= 0) 
    { 
     throw new ArgumentOutOfRangeException(name + " must be positive"); 
    } 
    return input; 
} 

public static double ValidateNonNegative(double input, string name) 
{ 
    if (input < 0) 
    { 
     throw new ArgumentOutOfRangeException(name + " must not be negative"); 
    } 
    return input; 
} 

Sau đó, bạn có thể viết:

public double AirDensity 
{ 
    get { return _airDensity; } 
    set 
    {    
     _airDensity = ValidationHelpers.ValidateNonNegative(value, 
                  "Air density"); 
    } 
} 

Nếu bạn cần điều này với nhiều loại hình, bạn thậm chí có thể làm cho nó chung chung:

public static T ValidateNonNegative(T input, string name) 
    where T : IComparable<T> 
{ 
    if (input.CompareTo(default(T)) < 0) 
    { 
     throw new ArgumentOutOfRangeException(name + " must not be negative"); 
    } 
    return input; 
} 

Lưu ý rằng không ai trong số này là terribly i18n- thân thiện ...

+0

Cảm ơn bạn đã cải thiện mã. Nhưng tôi đã không hiểu ý của bạn về "thân thiện với i18" ... –

+0

@archer: Các thông điệp được mã hóa cứng như tiếng Anh. Bạn sẽ có nhiều công việc hơn trước bạn nếu bạn muốn dịch chúng sang một ngôn ngữ khác. –

+0

OK. Cảm ơn bạn đã giải thích. –

3

Tất cả phụ thuộc vào công nghệ bạn đang sử dụng - nếu bạn dưới MVC, bạn có thể sử dụng Thuộc tính, như thế này;

http://msdn.microsoft.com/en-us/library/ee256141(v=vs.98).aspx

+1

OP không nói về xác thực giao diện người dùng ... –

+0

Cả I - thuộc tính MVC đều xử lý cả xác thực phía máy khách và phía máy chủ (xem phương thức Model.IsValid) –

1

Hãy thử sử dụng phương thức như vậy:

public void FailOrProceed(Func<bool> validationFunction, Action proceedFunction, string errorMessage) 
    { 
     // !!! check for nulls, etc 
     if (!validationFunction()) 
     { 
      throw new ArgumentOutOfRangeException(errorMessage); 
     } 

     proceedFunction(); 
    } 
1

Bạn có thể đạt được điều này sử dụng lớp từ System.ComponentModel.DataAnnotations

class Tunnel 
{ 
    [Range(0, double.MaxValue, ErrorMessage = "Length must be positive value.")] 
    public double Length { get; set; } 
} 

Validation:

var tunnel = new Tunnel { Length = 0 }; 
var context = new ValidationContext(tunnel, null, null); 
Validator.ValidateObject(tunnel, context, true); 

Ngoài ra, bạn có thể thực hiện xác nhận của riêng bạn thuộc tính trọng ValidationAttribute lớp

+0

Điều này có vẻ như nó sẽ giới thiệu một chút chi phí không? – Skizz

+0

@Skizz, Đó là xác thực bằng cách sử dụng các thuộc tính, không còn nữa. Tôi không thích thực hiện xác nhận bên trong accessor 'set'. –

+0

những gì tôi nhận được là kết nối thời gian chạy giữa thuộc tính và thuộc tính. Có lẽ .net làm gì đó thông minh ở đây. – Skizz

1

Sử dụng chức năng Validator tôi đã đề cập trong nhận xét của tôi ở trên, tôi muốn làm một cái gì đó như thế này (mã chưa được kiểm tra) :

void textBox_Changed(object sender, EventArgs e) { 
    submitButton.Enabled = validator(); 
} 

bool validator() { 
    const string NON_POSITIVE = "Value must be greater than Zero"; 
    bool result = false; 
    string controlName = "Length"; 
    try { 
    _length = Convert.ToDouble(txtLength.Text); 
    if (_length <= 0) throw new Exception(NON_POSITIVE); 
    controlName = "Cross Section Area"; 
    _crossSectionArea = Convert.ToDouble(txtCrossSectionArea.Text); 
    if (_crossSectionArea <= 0) throw new Exception(NON_POSITIVE); 
    controlName = "Air Density"; 
    _airDensity = Convert.ToDouble(txtAirDensity.Text); 
    if (_airDensity <= 0) throw new Exception(NON_POSITIVE); 
    result = true; // only do this step last 
    } catch (Exception err) { 
    MessageBox.Show(controlName + " Error: " + err.Message, "Input Error"); 
    } 
    return result; 
} 

John Skeet có thể có cách tốt hơn, nhưng điều này có hiệu quả. :)

3

Dưới đây là phiên bản của tôi, đó là một chút sạch hơn phiên bản Jon trong một số khía cạnh:

interface IValidator <T> 
{ 
    bool Validate (T value); 
} 

class IntValidator : IValidator <int> 
{ 
    public bool Validate (int value) 
    { 
    return value > 10 && value < 15; 
    } 
} 
class Int2Validator : IValidator<int> 
{ 
    public bool Validate (int value) 
    { 
    return value > 100 && value < 150; 
    } 
} 

struct Property<T, P> where P : IValidator<T>, new() 
{ 
    public T Value 
    { 
    set 
    { 
     if (m_validator.Validate (value)) 
     { 
     m_value = value; 
     } 
     else 
     { 
     Console.WriteLine ("Error validating: '" + value + "' is out of range."); 
     } 
    } 

    get { return m_value; } 
    } 

    T m_value; 
    static IValidator<T> m_validator=new P(); 
} 

class Program 
{ 
    static void Main (string [] args) 
    { 
    Program 
     p = new Program(); 

    p.m_p1.Value = 9; 
    p.m_p1.Value = 12; 
    p.m_p1.Value = 25; 
    p.m_p2.Value = 90; 
    p.m_p2.Value = 120; 
    p.m_p2.Value = 250; 
    } 

    Property<int, IntValidator> 
    m_p1; 

    Property<int, Int2Validator> 
    m_p2; 
} 
Các vấn đề liên quan