c# - 保护价值与数据的方法?
问题描述
有谁知道防止无效数据而不是无效值的任何技术或方法?我知道这似乎是一个奇怪的区别,但请耐心等待。
我最近提出了一个关于更好的方法来处理防止无效变量值的问题。我们目前正在将异常包装在一个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");
所以我试图在这里找到更好的方法,这就是我绊倒的地方。到目前为止,我所遇到的问题是,我的问题从根本上是这样一个事实,即我正在考虑作为数据保护什么(“我需要防范不良客户 ID”),但我正在保护价值观(“我需要确保该整数至少为 1")。
我不知道从这里去哪里。我觉得这可能是其中之一“我不知道它存在,但这有帮助!” 案例。
有人对看什么有任何建议吗?到目前为止,我有三个想法,我不确定一个是否比另一个更好,或者是否有某种方法可以将它们结合起来达到我的目标:
- 代码合同
- 我缺少的一些设计模式
- 其他一些技术或技巧(例如,属性
InvokerParameterName
??)
最后一点:我知道 ReSharper 提供了一个 Annotations 库,但不是我团队中的每个人(包括我)都使用 ReSharper,所以我不想依赖它。
解决方案
这并不能完全回答您的问题,但这是我在评论中所说的:
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.'
您可能想要做的另一件事是将它变成一个可实例化的类,所有方法都是实例方法。您创建该类的一个实例,针对该实例执行所有断言,最后,您断言一切都很好。如果不是,则将所有故障一起吐出(在一个例外中)。
这样,您的所有测试都在抛出异常之前完成。
推荐阅读
- postgresql - PostgreSQL select now()::timestamp 不同于默认 now()::timestamp
- java - 指标,气味:如何在我的遗留产品 Java 存储库中找到最长(以代码行计)的方法?
- amazon-web-services - Authorizer 中请求的 AWS API Gateway 标头
- mysql - 如何从其他电脑访问 mysql 数据库?
- erlang - 无法从 iq 接收隶属关系变更通知
- php - 如何在mysql数据库中找到特定的日期数据或下一个日期数据?
- batch-file - 编写从用户输入运行 robocopy 的批处理文件
- javascript - 使用淘汰赛js在点击选项上上下移动数组值?
- jquery - axios 发布请求和 JQuery $.ajax 请求都在移动设备上返回 403 禁止错误
- delphi - 记录在 TDictionary