类属性内部的验证

本文关键字:验证 内部 属性 | 更新日期: 2023-09-27 17:58:33

代码如下:

public class MyEvent
{
    public string EventTitle { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public bool IsInsideSameMonth
    {
        get
        {
            // No code is bug-free, so we assume this situation may occur somehow.
            if (StartDate > EndDate)
            {
                // And when this occurs, we want to halt the application by throwing exception to prevent further potential damage.
                throw new MyEventException("Start date is not supposed to be greater than end date.");
            }
            return (StartDate.Year == EndDate.Year && StartDate.Month == EndDate.Month);
        }
    }
    public void Validate()
    {
        if (StartDate > EndDate)
        {
            throw new MyEventException("Start date is not supposed to be greater than end date.");
        }
        if (String.IsNullOrWhiteSpace(EventTitle))
        {
            throw new MyEventException("Title cannot be empty.");
        }
    }
}
public class MyEventException : Exception
{
    public MyEventException(string message)
        : base(message)
    {
    }
}

我在IsInsideSameMonth属性中执行StartDate > EndDate验证似乎是多余的。我只是更喜欢安全一点。但感觉好像我做错了什么,但我无法描述

这是个好做法吗?请分享您的宝贵经验和想法。

类属性内部的验证

您不应该使用Auto实现的属性。相反,您应该使用一个支持私有字段,然后在设置属性时进行检查,如:

private DateTime _StartDate;
public DateTime StartDate
{
    get { return _StartDate; }
    set
    {
        if (value > _EndDate)
        {
            throw new MyEventException("Start date is not supposed to be greater than end date.");
        }
        else
        {
            _StartDate = value;
        }
    }
}
private DateTime _EndDate;
public DateTime EndDate
{
    get { return _EndDate; }
    set { _EndDate = value; }
}

您当前的代码将允许用户将StartDate设置为任何值,并且只有在检查属性IsInsideSameMonth时才能实现。

对于EventTitle,您可以声明一个支持字段,并在属性的setter中进行验证。类似这样的东西:

string eventTitle;
public string EventTitle
{
    get
    { 
        return eventTitle;
    }
    set
    {
        if(!IsNullOrWhiteSpace(value))
            eventTitle = value;
        else
            throw new MyEventException("Title cannot be empty.");
    }
}

至于DateTime对象,您可以遵循相同的路径:

private DateTime startDate;
public DateTime StartDate
{
    get 
    {
        return startDate; 
    }
    set
    {
        if (value > EndDate)
        {
            throw new MyEventException("Start date is not supposed to be greater than end date.");
        }
        else
        {
            startDate = value;
        }
    }
}
private DateTime endDate;
public DateTime EndDate
{
    get 
    { 
        return endDate; 
    }
    set 
    {   
       endDate = value; 
    }
}

设置属性时最好控制值,因此您需要将自动属性转换为旧样式(带有私有字段的属性),并在那里进行检查。

这是Microsoft房地产设计指南。

下面是一个在设置时检查值的示例,如果无效则抛出。我还定义了验证功能,以减少冗余代码(如果你想更改验证或错误消息,它将在一个位置)。

public class MyEvent
{
    public bool IsInsideSameMonth
    {
        get
        {
            return (StartDate.Year == EndDate.Year && StartDate.Month == EndDate.Month);
        }
    }
    private string _EventTile;
    public string EventTitle
    {
        get { return _EventTile; }
        set
        {
            ValidateTitle(value); // this will throw if invalid and leave the value of _EventTitle unchanged
            _EventTile = value;
        }
    }
    private DateTime _StartDate  = DateTime.MinValue;;
    public DateTime StartDate
    {
        get { return _StartDate; }
        set
        {
            ValidateDates(value, EndDate); // this will throw if invalid and leave the value of _StartDate unchanged
            _StartDate = value;
        }
    }
    private DateTime _EndDate  = DateTime.MaxValue;;
    public DateTime EndDate
    {
        get { return _EndDate; }
        set
        {
            ValidateDates(StartDate, value); // this will throw if invalid and leave the value of _EndDate unchanged
            _EndDate = value;
        }
    }
    private void ValidateDates(DateTime start, DateTime end)
    {
        if (start > end)
        {
            throw new MyEventException("Start date is not supposed to be greater than end date.");
        }
    }
    private void ValidateTitle(string title)
    {
        if (String.IsNullOrWhiteSpace(title))
        {
            throw new MyEventException("Title cannot be empty.");
        }
    }
    public void Validate()
    {
        ValidateDates(StartDate, EndDate);
        ValidateTitle(EventTitle);
    }
}
public class MyEventException : Exception
{
    public MyEventException(string message)
        : base(message)
    {
    }
}