首页 > 解决方案 > 保护价值与数据的方法?

问题描述

有谁知道防止无效数据而不是无效的任何技术或方法?我知道这似乎是一个奇怪的区别,但请耐心等待。

我最近提出了一个关于更好的方法来处理防止无效变量值的问题。我们目前正在将异常包装在一个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")。

我不知道从这里去哪里。我觉得这可能是其中之一“我不知道它存在,但这有帮助!” 案例。

有人对看什么有任何建议吗?到目前为止,我有三个想法,我不确定一个是否比另一个更好,或者是否有某种方法可以将它们结合起来达到我的目标:

最后一点:我知道 ReSharper 提供了一个 Annotations 库,但不是我团队中的每个人(包括我)都使用 ReSharper,所以我不想依赖它。

标签: c#validationdesign-patterns

解决方案


这并不能完全回答您的问题,但这是我在评论中所说的:

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.'

您可能想要做的另一件事是将它变成一个可实例化的类,所有方法都是实例方法。您创建该类的一个实例,针对该实例执行所有断言,最后,您断言一切都很好。如果不是,则将所有故障一起吐出(在一个例外中)。

这样,您的所有测试都在抛出异常之前完成。


推荐阅读