繁体   English   中英

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

[英]Which technique is correct if not using exceptions?

假设我有这样的课程

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

}

或者一些验证员类或......我猜其他一些东西。 所以我只想为自己制定标准 - 哪种技术更好,什么时候......

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

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

这个解决方案的另一点:

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

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

常见的方法是在这种情况下引发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是否在范围内。

有用的链接:

我试着给出一些流程如何决定在这里使用什么:

如果您不希望频繁出现“无效”案例,最后请使用例外。

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标志,如示例所示。 但请注意,您将检测/检查问题的可能性转移给呼叫者。 例外情况会更好,因为您必须处理它们,否则您将受到直接惩罚。

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

我希望这些提示很有帮助。

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

例如:

public bool IsValueValid(xxx)
{

}

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

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

坚持

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM