有人知道防止无效的数据而不是无效的 values 的任何技术或方法吗?我知道这似乎是一个奇怪的区别,但请忍受。
最近,我想到了一个更好的方法来防范无效变量值。目前,我们将异常包装在Guard
类中,但是建议更进一步,将那些包装在Extensions中。换句话说:
int myVar = 0;
// Basic
if (myVar < 1) throw new InvalidArgumentException("myVar cannot be less than 1");
// Guard -- wraps the above exception
Guard.AgainstValuesLessThan(1, myVar, nameof(myVar), "Value cannot be less than 1");
// Extension -- wraps the above guard
myVar.EnsureValid();
我在这里的问题是,感觉就像乌龟一样,一直下来-最终,我们将决定扩展名不起作用,并用其他东西包装扩展名。此外,对原语的扩展使您很难确定要保护的内容以及原因-想象以下情况:
int customerId = 1;
int employeeId = 1;
// How do I write an extension method that lets me say "Guard against invalid Customer
// IDs" and "Guard against invalid Employee IDs"? Both are ints. This method allows a
// guard, but with no context.
public static void EnsureValidValue(this int actual, int expected, string msg);
employeeId.EnsureValidValue(1, "Employee ID can't be less than 1");
customerId.EnsureValidValue(1, "Customer ID can't be less than 1");
所以我试图在这里找到一种更好的方法,这就是我绊倒的地方。到目前为止,我所遇到的问题是,我的问题从根本上说是我正在考虑将什么作为 data 保护(“我需要防止不良的客户ID”),但是我保护值(“我需要确保该整数至少为1”)。
我不确定从这里去哪里。我觉得这可能是“我不知道那个存在,但有帮助!”之一。案例。
有人对看什么有任何建议吗?到目前为止,我有3种想法,我不确定一种想法是否比另一种更好,或者是否有某种方法可以将它们结合起来以达到我的目标:
InvokerParameterName
?)最后一点:我知道ReSharper提供了一个Annotations库,但并非团队中的每个人都使用ReSharper(包括我在内),所以我不想依赖它。
答案 0 :(得分:1)
这并不能完全回答您的问题,但这是我在评论中谈论的内容:
public static class AssertValid
{
public static void TestAssertValid()
{
var customerId = 0;
AssertValid.MinimumFor(customerId, 1, nameof(customerId));
}
public static void RangeFor<T>(T variableValue, T min, T max, string varName,
string message = "Variable {0} outside of range {1} to {2} in function {3}",
[CallerMemberName] string inFunc = "") where T : IComparable
{
if (variableValue.CompareTo(min) < 0 || variableValue.CompareTo(max) > 0)
{
var msg = string.Format(message, varName, min, max, inFunc);
throw new ArgumentOutOfRangeException(varName, variableValue, msg);
}
}
public static void MinimumFor<T>(T variableValue, T min, string varName,
string message = "Variable {0} less than minimum of {1} in function {2}",
[CallerMemberName] string inFunc = "") where T : IComparable
{
if (variableValue.CompareTo(min) < 0)
{
var msg = string.Format(message, varName, min, inFunc);
throw new ArgumentOutOfRangeException(varName, variableValue, msg);
}
}
public static void MaximumFor<T>(T variableValue, T min, string varName,
string message = "Variable {0} greater than maximum of {1} in function {2}",
[CallerMemberName] string inFunc = "") where T : IComparable
{
//...
}
public static void StringLengthRangeFor(string variableValue, int min, int max, string varName,
string message = "Length of string variable {0} outside of range {1} to {2} in function {3}",
[CallerMemberName] string inFunc = "")
{
if (variableValue.Length < min || variableValue.Length > max)
{
var msg = string.Format(message, varName, min, max, inFunc);
throw new ArgumentOutOfRangeException(varName, variableValue, msg);
}
}
public static void StringLengthMinFor(string variableValue, int min, int max, string varName,
string message = "Length of string variable {0} less than {1} characters in function {2}",
[CallerMemberName] string inFunc = "")
{
if (variableValue.Length < min)
{
var msg = string.Format(message, varName, min, inFunc);
throw new ArgumentOutOfRangeException(varName, variableValue, msg);
}
}
public static void StringLengthMaxFor(string variableValue, int max, string varName,
string message = "Length of string variable {0} greater than {1} characters in function {2}",
[CallerMemberName] string inFunc = "")
{
//...
}
public static void StringLengthPatternFor(string variableValue, string regexPattern, string varName,
string message = "String variable {0} does not match acceptable pattern in function {1}",
[CallerMemberName] string inFunc = "")
{
//... Use ArgumentException
}
}
然后,如果您有类似的内容(在名为TestAssertValid
的函数中):
var customerId = 0;
AssertValid.MinimumFor(customerId, 1, nameof(customerId));
您最终遇到如下异常:
System.ArgumentOutOfRangeException: 'Variable customerId less than minimum of 1 in function TestAssertValid
Parameter name: customerId
Actual value was 0.'
您可能想要做的另一件事是将其放入一个可实例化的类中,所有方法均为实例方法。您创建该类的一个实例,对该实例执行所有声明,最后,您声明一切都很好。如果不是,则将所有故障吐出(一个例外)。
这样,您的所有测试都在引发异常之前完成。
答案 1 :(得分:0)
从可维护性的角度来看,我认为某些OOP /设计模式将是最好的方法。我同意您的看法,如果不是所有开发人员都需要使用ReSharper,请尝试将其嵌入代码中。
拥有Guard子句的方式很简单,并且易于重用;我不会改变这一点。如果我对您的理解正确,那么您就在防范业务规则,不一定是基本价值观。您希望封装“不能具有小于1的ID”的业务规则,这绝对是一个不错的规则。
建议您考虑以下几种选择:
public Employee(int id)
{
Guard.AgainstValuesLessThan(1, id, nameof(id), "Employee ID cannot be less than 1");
}
如果在代码的其他地方使用该对象,则可以肯定地知道它处于有效状态,因为您已成功构造了该对象。这也解决了记住在调用者函数/类中调用Guard子句的问题。
我倾向于首先选择选项1,因为它可以帮助您专注于创建具有有效状态的对象,这是一个很好的遵循原则。如果您需要更多示例,或者我想念您的问题,请让我知道,我可以给出更好的答案:)