我写了一个快速的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})");
}
答案 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;
}