C# 从属性设置器中抛出什么异常?

C# 从属性设置器中抛出什么异常?,c#,validation,exception,properties,C#,Validation,Exception,Properties,我有一个字符串属性,它有一个最大长度要求,因为数据链接到数据库。如果调用方试图设置超过此长度的字符串,我应该抛出什么异常 例如,此C#代码: 我考虑了ArgumentException,但它似乎并不正确。从技术上讲,它是一个函数-MyProperty\u set(string value),因此可以使用ArgumentException,但在消费者眼中,它不是作为函数调用的-它位于赋值运算符的右侧 这个问题可能还可以扩展到包括在属性设置程序中完成的所有类型的数据验证,但我对上述情况特别感兴趣。您

我有一个字符串属性,它有一个最大长度要求,因为数据链接到数据库。如果调用方试图设置超过此长度的字符串,我应该抛出什么异常

例如,此C#代码:

我考虑了
ArgumentException
,但它似乎并不正确。从技术上讲,它是一个函数-
MyProperty\u set(string value)
,因此可以使用
ArgumentException
,但在消费者眼中,它不是作为函数调用的-它位于赋值运算符的右侧


这个问题可能还可以扩展到包括在属性设置程序中完成的所有类型的数据验证,但我对上述情况特别感兴趣。

您可以使用InvalidOperationException。这是一种妥协。我也不想麻烦使用ArgumentException。

在类似的情况下,例如System.String.StringBuilder.Capacity Microsoft使用ArgumentOutOfRangeException()查看带有Reflector的mscorlib.dll,类似于:

public int PropertyA
{
    get
    {
        return //etc...
    }
    set
    {
        if (condition == true)
        {
            throw new ArgumentOutOfRangeException("value", "/* etc... */");
        }
        // ... etc
    }
}

对我来说,ArgumentException(或子对象)更有意义,因为您提供的参数(值)无效,这就是创建ArgumentException的目的。

我根本不会抛出异常。相反,我希望允许一个任意长度的字符串,然后在保存之前对调用的类使用单独的“Validate”方法。有很多场景,特别是当您使用数据绑定时,从属性设置器抛出异常可能会让您陷入混乱

从属性设置器抛出异常的问题在于程序员忘记捕捉它们。这在某种程度上取决于你期望得到的数据有多干净。在这种情况下,我希望长字符串长度是常见的而不是异常的,因此使用异常将是“带异常的流控制”

引用微软的:

不要对正常流使用异常 如果可能的话。除了 系统故障和使用 潜在的竞争条件、框架 设计人员应该设计API,以便 用户可以编写不需要的代码 抛出异常。例如,你可以 提供检查前提条件的方法 在调用成员之前,让用户 可以编写不抛出错误的代码 例外情况


还记得计算机科学中有多少问题是通过增加一个额外的间接层次来解决的吗

一种方法是创建一个新类型,比如FixedLengthString。这种类型的实例将验证它们初始化时使用的字符串的长度——使用转换运算符从普通字符串进行类型转换。如果属性设置器将此类类型作为其参数,则任何冲突都将成为类型转换异常,而不是参数/属性异常


实际上,我很少这样做。它闻起来有点让OO走得太远了——但在某些情况下,它可能是一种有用的技术,因此为了完整起见,我在这里提到它。

尽可能使用现有的异常。在这种情况下,请使用InvalidOperationException,因为传入值使对象处于不一致的状态。当需要对自定义异常进行特定处理时,可以创建自定义异常。在这种情况下,您只会抛出包含一些文本的异常,因此请使用InvalidOperationException

抛出InvalidOperationException时,显示已传递给此setter的值

public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}

虽然我个人完全不同意(验证毕竟是setter的工作——否则,除了简单的field=value;return field;getters/setters之外,没有其他任何意义——我喜欢你提出数据绑定的观点,这确实会让你陷入混乱。在属性setter中抛出异常是可以的,但我不会在属性getters中抛出异常。延迟抛出异常将不允许捕获违规者。此外,如果程序员忘记捕获异常,它将跳到他的脸上,而不是无意中冒出来。@Trap:我想这取决于您设计类的目的。如果您希望将数据绑定到类的对象,则不会希望当用户键入一对多个字符时它会爆炸。实现System.ComponentModel.IDataErrorInfo是解决此问题的标准方法。在setter中,您设置了一个名为IsMyPropertyToLong的内部标志,而不是引发异常。稍后,您可以使用此标志从[string]返回正确的错误消息ArgumentException和ArgumentOutOfRangeException是,它们在这里被正确地用于检查约束。如果用户得到这些可预防的异常,那就是他们代码中的错误。“ArgumentOutOfRangeException-当参数值超出所调用方法定义的允许值范围时引发的异常"……IMO,MMOO应该修正它们的代码。在这里确认:当然,你可以拥有两个世界中最好的,并创建自己的异常类型,它来自于,例如,无效操作异常。当然,你仍然额外支付一点代码和代码复杂度。这是一个小的成本,但是在称重之后,你可能仍然认为它不值得进行无效操作。在这种情况下不应引发NexException。错误的是值,而不是设置值的操作。这一点很好,尽管这是针对空情况的。但是,它确实支持使用
ArgumentException
系列,因此+1作为引用。您如何处理传递设置为最多100个字符的FixedLengthString是否将设置为最多50个字符的FixedLengthString设置为属性?
public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}