如果不使用异常,哪种技术是正确的?

时间:2011-10-14 10:00:53

标签: c# .net

假设我有一个这样的课程

class A
{
    private int _x; //must be between [-10 10]
    private int _y; //must be between [10 20]
}

使用属性我有几个变量变体

public int X
{
    get { return _x; }
    set
    {
        if (!(value >= -10 && value <= 10))
            throw new Exception("Some error text");
        _x = value;
    }
}

public int X
{
    get { return _x; }
    set
    {
        if (!(value >= -10 && value <= 10))
            return;
        _x = value;
    }
}

(_y相同)。
在第一种情况下,我不确定我是否想要使用异常(它们很慢并且有其他已知问题)。第二,我付出的代价是不使用它们的价值模糊(对于_x和_y以某种不同的方式)。 显然我可以在我的情况下使用(如果处理对象列表)就像那样

public bool IsValid = true;
//...
public int X
{
    get { return _x; }
    set
    {
        if (!(value >= -10 && value <= 10))
        {
            IsValid = false;
            return;
        }
        _x = value;
    }
}
class AWrapper
{
    public List<A> AList {get; set;}
    public AWrapper(List<A> list)
    {
        AList = list.Where(x => x.IsValid == true).ToList();
    }

}

或某些validator class或......我想其他一些事情。 所以我只想为自己制定标准 - 哪种技术更好,什么时候......

6 个答案:

答案 0 :(得分:7)

让我们直接开始;例外情况可能“缓慢”,但这正是您在特殊情况下仅使用它们的原因。

在你的情况下,如果超出给定范围的数字是Exceptional(即,永远不会发生)那么你可以抛出异常。但是,如果这类似于用户输入,那么填写超出可接受范围的值的用户肯定是例外!在这种情况下,您想要的是验证输入的值是否在可接受的范围内。

此解决方案的另一点:

set
{
    if (!(value >= -10 && value <= 10))
        return;
    _x = value;
}

这,IMO,同样糟糕(如果不是更糟)。原因是,如果我设置X=10,我希望当我阅读X时,它具有我刚设置的值。

答案 1 :(得分:2)

通常的做法是在这种情况下提出InvalidArgumentException。如果您不想处理异常,可以引入自定义标记IsValid(如您所述)。

为了保留属性范围,我建议为此目的引入自定义属性,并通过它标记属性,如:

public bool IsValid { }

[ValueRange(Max = 10, Min = 5)]
public int X
{
    set
    {
       this.ValidateValueRange(this.X, value);
    }
}

private bool ValidateValueRange(...)
{
   // 1. Get property value (see link below regarding retrieving a property)
   // 2. Get ValueRange attribute values
   // 3. Update this.IsValid
   // 4. Return ...
}

然后实现单一方法来检查传入value是否在范围内。

有用的链接:

答案 2 :(得分:2)

我尝试给出一些流程来决定在这里使用什么:

如果您不希望频繁发生“无效”案件,最终可以使用例外。

set
{
    if (!(value >= -10 && value <= 10))
        throw new Exception("Some error text");
    _x = value;
}

否则,如果您需要最高性能并且可以接受,则可以记录您的setter并声明该范围之外的所有值都被忽略。

set
{
    if (value >= -10 && value <= 10)
        _x = value;
    // else optionally log something
}

如果无法选择静默忽略不正确的值,请在示例中添加日志记录或IsValid标志。但请注意,您将检测/检查问题的可能性转移给呼叫者。例外情况更好,因为你必须处理它们,否则你会受到直接惩罚。

在另一个答案中使用自定义属性只是实现检查的另一种方式。

我希望这些提示很有用。

答案 3 :(得分:0)

.Net中用于检查值有效性的标准模式是创建一个首先检查值的方法,让类的用户调用它并处理结果并在此之后抛出异常。

例如:

public bool IsValueValid(xxx)
{

}

public void SetValue(xxx)
{
    if(!this.IsValueValid())
    {
        throw Exception();
    }
}

通常,必须存储值的类不知道如何处理无效值,调用者的工作就是知道如何处理该值。

答案 4 :(得分:0)

坚持

public int X
{
    get { return _x; }
    set
    {
        if (!(value >= -10 && value <= 10))
            throw new Exception("Some error text");
        _x = value;
    }
}

答案 5 :(得分:0)

如果您想验证从UI收到的用户输入,那么我建议您使用Validator方法,其中您可以告知用户预期的内容。

在其他情况下,如果您决定不显示异常的成本并继续使用任何安全/默认值或使用自定义异常中断流,则需要权衡。