C#/TSQL 十进制边界检查 - 有更简洁的方法吗?

C# / TSQL decimal boundary check - Is there a cleaner way?

我写了一个快速的 c# 扩展方法,但不确定是否有更简洁的方法来完成我想做的事情。它确实有效,但使用字符串重复器并插入小数感觉有点老套。

目标是在应用程序级别,我们可以在将数据发送到数据库之前清理/修复任何数据问题以防止溢出。

注意:PCL 库,在这种情况下不能引用外部 DLL。

public static bool TsqlDecimalBoundariesCheck(this decimal valueToCheck, int precision, int scale)
    {
        if(scale > precision) throw new ArgumentException($"BOUNDARY CHECK: Scale [{scale}] must not be higher than Percision [{precision}]");

        // create X precision values of the value 9
        var precisionValue = new string('9', precision);

        // Insert the decimal place x positions from the right 
        if (scale > 0)
        {
            precisionValue = precisionValue.Insert((precision - scale), ".");
        }

        // Get the upper and lower values
        var upperBoundry = decimal.Parse(precisionValue);
        var lowerBoundry = upperBoundry * -1;

        return (valueToCheck <= upperBoundry) && (valueToCheck >= lowerBoundry);
    }

还有一些快速的单元测试:

    [TestMethod]
    public void TestBoundryConstraints()
    {
        var precision = 4;
        var scale = 1;

        var testValue = 1000m;
        var result = testValue.TsqlDecimalBoundariesCheck(precision , scale);
        Assert.IsFalse(result, $"Value {testValue} is expected to be outside Decimal({precision }, {scale})");

        testValue = -1000m;
        result = testValue.TsqlDecimalBoundariesCheck(precision , scale);
        Assert.IsFalse(result, $"Value {testValue} is expected to be outside Decimal({precision }, {scale})");

        testValue = 100m;
        result = testValue.TsqlDecimalBoundariesCheck(precision , scale);
        Assert.IsTrue(result, $"Value {testValue} is expected to be within Decimal({precision }, {scale})");

        testValue = 999.9m;
        result = testValue.TsqlDecimalBoundariesCheck(precision , scale);
        Assert.IsTrue(result, $"Value {testValue} is expected to be within Decimal({precision }, {scale})");

        testValue = -999.9m;
        result = testValue.TsqlDecimalBoundariesCheck(precision , scale);
        Assert.IsTrue(result, $"Value {testValue} is expected to be within Decimal({precision }, {scale})");
    }

因此,您绝对可以通过执行 (10^p - 1) * (10^-s) 来获取上限和下限,从而摆脱重复的骇人听闻的字符串。

如果您想检查以确保比例没有被截断,您可以实际截断它然后比较值。如果截断值和原始值相同,则比例有效。

把它们放在一起,你会得到这样的东西:

public static bool TsqlDecimalBoundariesCheck(this decimal valueToCheck, int precision, int scale)
{
    if (scale > precision) throw new ArgumentException($"BOUNDARY CHECK: Scale [{scale}] must not be higher than Percision [{precision}]");

    //Upper/lower bounds 
    var step = (decimal)Math.Pow(10, precision);
    var upperBoundry = (step - 1) * (decimal)Math.Pow(10, -scale);
    var lowerBoundry = -1 * upperBoundry;

    //Truncate decimal to scale   
    //If the truncated value does not equal the original, it must've been out of scale
    step = (decimal)Math.Pow(10, scale);
    var truncated = Math.Truncate(step * valueToCheck) / step;

    return (valueToCheck <= upperBoundry)
        && (valueToCheck >= lowerBoundry)
        && truncated == valueToCheck;
}