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

时间:2017-04-24 22:11:28

标签: c# tsql refactoring decimal code-cleanup

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

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

注意: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})");
    }

1 个答案:

答案 0 :(得分:0)

所以你绝对可以通过(10^p - 1) * (10^-s)来获取上限和下限来摆脱hacky字符串重复。

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

总而言之,你得到这样的东西:

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;
}