验证构造函数数据

时间:2009-08-26 22:59:26

标签: c# class-design structure

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

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

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

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);
    }
}

5 个答案:

答案 0 :(得分:2)

嗯,对于一个,你可能会得到可怕的NullReferenceException,因为你没有检查emailAddress在任何级别是否为null。该特定检查应在构造函数本身中完成,如果emailAddress为null,则抛出ArgumentNullException。至于其余部分,我没有看到任何特殊问题,因为它是在你的样本中写的。但是,如果将属性设置为虚拟,并从此类派生子级,则可能会出现一些问题。字段初始化,基类和派生类构造函数的执行顺序就成了一个问题,你必须要小心。

答案 1 :(得分:2)

是的,如果您的一般方法是:

  

确保您只能获取valid对象的实例

然后我喜欢它。

构造函数应该用于创建立即有效的对象,而不是仅仅为了放置东西而创建一个“容器”。

答案 2 :(得分:2)

对我来说,不在构造函数中验证数据是没有意义的。正如您所指出的,对象最终可能处于无效状态。鉴于这种设计,你甚至不会意识到在调用getter时你有错误的数据。

对于任何中等复杂度或更高复杂度的东西,我倾向于使用破碎规则方法而不是立即抛出异常。在该方法中,我定义了一个BrokenRules对象,该对象包含有关无效的类和属性的信息,以及它无效的原因。然后,在一个公共基类中,我定义一个List来保存关于该对象的所有“错误”的列表。属性(同样在基类中)IsValid指示当前是否存在任何破坏的规则。

这样做的好处是对象状态可能存在一些问题。如果要求用户更正问题(即,该对象是从UI设置的),则提供所有问题的列表允许用户一次性纠正它们,而不是修复一个错误只是为了告诉另一个错误。而另一个。等

答案 3 :(得分:0)

我认为这种做法没有错。你可以在构造函数中调用这个方法,属性setter / getters只是方法调用的语法糖。

答案 4 :(得分:0)

设置电子邮件地址时会进行验证。这是您想要的地方,因为以后可能会再次设置电子邮件地址。

如果您还在构造函数中调用了验证,那么您将进行额外的冗余验证调用(一次构建时,另一个在构造函数中设置电子邮件地址时)。