3

“C# 类设计手册”(第 137 页)中的示例类不会从仅类构造函数内部调用特定字段的类验证方法。因此,基本上示例类允许您创建一个包含错误数据的对象,并且只有在您调用该字段的属性时才会对该数据抛出错误,然后对其进行验证。所以你现在有一个坏对象,直到事后才知道。

我一直不明白为什么他们不只是从构造函数中调用属性,因此如果在初始化期间发现错误数据会立即抛出错误?我已经给他们发邮件了,没有用...

我倾向于通过从我的构造函数调用我的属性来使用以下格式 - 这是验证初始化数据的正确结构吗?泰

class Foo
{
    private string _emailAddress;

    public Foo(string emailAddress)
    {
        EmailAddress = emailAddress;
    }

    public string EmailAddress
    {
        get { return _emailAddress; }
        set
        {
            if (!ValidEmail(value))
                throw new ArgumentException
                    (string.Format
                    ("Email address {0} is in wrong format", 
                    value));

            _emailAddress = value;
        }
    }


    private static bool ValidEmail(string emailAddress)
    {
        return Regex.IsMatch
            (emailAddress, @"\b[A-Z0-9._%+-]+" +
                           @"@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
                           RegexOptions.IgnoreCase);
    }
}
4

5 回答 5

2

Well, for one, you are likely to get the dreaded NullReferenceException, since you are not checking if emailAddress is null at any level. That particular check should be done in the constructor itself, and if emailAddress IS null, throw an ArgumentNullException. As for the rest, I don't see any particular problems with it as it is written in your sample. However, there are some issues that may arise if you make the property virtual, and derive children from this class. Execution order of field initialization, base and derived class consturctors then becomes an issue, and you have to be careful.

于 2009-08-26T23:03:10.607 回答
2

Yes, if your general approach is:

Ensure that you can only get an instance of a valid object

then I love it.

Constructors should be used to create objects that are immediately valid, not to create just a 'container', for things to be put in.

于 2009-08-26T23:03:31.293 回答
2

It makes no sense to me not to validate data in the constructor. As you point out, the object can end up in an invalid state. Given this design, you would not even realize that you had bad data when calling the getter.

For anything of moderate complexity or higher, I tend to use a Broken Rules approach rather than immediately throwing an Exception. In that approach, I define a BrokenRules object that contains information about the class and property that is invalid, and the reason that it is invalid. Then, in a common base class, I define a List to hold a list of everything "wrong" about the object. A property (again in the base class) IsValid indicates whether there are presently any broken rules.

The advantage of this is that there could potentially be several things wrong with the object state. If a user is being asked to correct the problems (i.e. this object is set from a UI), providing a list of all problems lets the user correct them in one go, rather than fixing one error just to be told there is another one. And another one. Etc.

于 2009-08-26T23:07:05.920 回答
0

I see nothing wrong with this approach. You can call methods on this within the constructor, and property setters/getters are just syntactic sugar for method calls.

于 2009-08-26T23:03:23.260 回答
0

the validation is happening when the Email address is set. This is where you want it because the email address could potentially be set again later.

If you also called validation in the constructor, you'd be making an extra, redundant validation call (once when constructed, another when the email address is set in the constructor).

于 2009-08-26T23:04:45.503 回答