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