假设我有一个这样的课程
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或......我想其他一些事情。 所以我只想为自己制定标准 - 哪种技术更好,什么时候......
答案 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方法,其中您可以告知用户预期的内容。
在其他情况下,如果您决定不显示异常的成本并继续使用任何安全/默认值或使用自定义异常中断流,则需要权衡。