MRE: https://dotnetfiddle.net/M7WeMH
我有这个通用的实用程序:
static T readValue<T>(string value)
{
return (T)Convert.ChangeType(value, typeof(T));
}
从一个应该都是decimal
值的文件中读取一些数据,当文本是科学符号时,例如"1E-5"
,我会得到一个异常-这种情况在文件中很少发生。进一步测试,我发现decimal.Parse
有同样的问题:
using System;
public class Program
{
static T readValue<T>(string value)
{
return (T)Convert.ChangeType(value, typeof(T));
}
public static void Main()
{
try
{
Console.WriteLine($"{readValue<decimal>("1E-5")}");
}
catch(Exception e)
{
Console.WriteLine(e);
}
try
{
Console.WriteLine($"{decimal.Parse("1E-5")}");
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
}
系统。FormatException:输入字符串格式不正确。
at System.Number。ThrowOverflowOrFormatException (ParsingStatus状态,类型代码类型)在System.Number。ParseDecimal (ReadOnlySpan 1的值,NumberStyles样式,NumberFormatInfo信息)System.Convert。ToDecimal(字符串值,IFormatProvider提供程序)atSystem.String.System.IConvertible。ToDecimal (IFormatProvider提供者)在System.Convert。ChangeType(对象值,类型)在System.Convert.ChangeType(Object . changetype)值,类型转换类型)在程序。readValue[T](String value)
at Program.Main()系统。FormatException:输入字符串格式不正确。
at System.Number。ThrowOverflowOrFormatException (ParsingStatus状态,类型代码类型)在System.Number。ParseDecimal (ReadOnlySpan 1的值,NumberStyles样式,NumberFormatInfo信息)System.Decimal。在Program.Main()
这个问题解释了如何修复对于decimal.Parse
(从指数表示法解析一个数字),但我这个通用的方法是用于加载各种文件数据从CSV文件在许多地方…是否有类似的修复方法来避免大量的代码重构?
这看起来很难看,但这里有一个如何实现特定类型行为的示例:
static T readValue<T>(string value) where T : struct
{
var type = typeof(T);
if (type == typeof(decimal))
{
// Put this return statement in a block that verifies the content of the string is scientific notation.
return (T)Convert.ChangeType(decimal.Parse(value, NumberStyles.Float), typeof(T));
}
return (T)Convert.ChangeType(value, typeof(T));
}
原因是Decimal.Parse
和Decimal.TryParse
使用的默认样式是这样的
[ws][sign][digits,]digits[.fractional-digits][ws]
不允许使用指数。如果你阅读Parse的文档,你会看到完整的数字格式是
[ws][$][sign][digits,]digits[.fractional-digits][e[sign]digits][ws]
,
e: 'e'或'e'字符,表示该值以指数表示法表示。如果
style
包含NumberStyles.AllowExponent
标志,则参数s可以用指数表示法表示一个数字。
这意味着您需要像上面那样使用NumberStyles.Float
(其中包括NumberStyles.AllowExponent
)才能使其工作。一些简单的演示:
var style = System.Globalization.NumberStyles.Float;
var culture = CultureInfo.GetCultureInfo("en-US");
string s = "1E-5";
var i = decimal.Parse(s, style);
decimal dec = 0;
decimal.TryParse(s, style, culture, out dec);