Convert.ChangeType 十进制不接受“1E-5”科学记数法,如何解决?
Convert.ChangeType doesn't accept "1E-5" scientific notation for Decimal, how to fix?
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);
}
}
}
System.FormatException: Input string was not in a correct format.
at System.Number.ThrowOverflowOrFormatException(ParsingStatus status,
TypeCode type) at System.Number.ParseDecimal(ReadOnlySpan`1 value,
NumberStyles styles, NumberFormatInfo info) at
System.Convert.ToDecimal(String value, IFormatProvider provider) at
System.String.System.IConvertible.ToDecimal(IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType,
IFormatProvider provider) at System.Convert.ChangeType(Object
value, Type conversionType) at Program.readValue[T](String value)
at Program.Main()
System.FormatException: Input string was not in a correct format.
at System.Number.ThrowOverflowOrFormatException(ParsingStatus status,
TypeCode type) at System.Number.ParseDecimal(ReadOnlySpan`1 value,
NumberStyles styles, NumberFormatInfo info) at
System.Decimal.Parse(String s) at Program.Main()
这个问题解释了如何修复它 for decimal.Parse
(Parse a Number from Exponential Notation) 但是我这个通用方法用于从许多地方的 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
and Decimal.TryParse
使用的默认样式是这样的
[ws][sign][digits,]digits[.fractional-digits][ws]
不允许指数。如果您阅读 Parse's documentation,您会看到完整的数字格式是
[ws][$][sign][digits,]digits[.fractional-digits][e[sign]digits][ws]
哪里
e: The 'e' or 'E' character, which indicates that the value is represented in exponential notation. The s parameter can represent a number in exponential notation if style
includes the NumberStyles.AllowExponent
flag.
这意味着您需要像上面那样使用 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);
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);
}
}
}
System.FormatException: Input string was not in a correct format.
at System.Number.ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type) at System.Number.ParseDecimal(ReadOnlySpan`1 value, NumberStyles styles, NumberFormatInfo info) at System.Convert.ToDecimal(String value, IFormatProvider provider) at System.String.System.IConvertible.ToDecimal(IFormatProvider provider) at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) at System.Convert.ChangeType(Object value, Type conversionType) at Program.readValue[T](String value)
at Program.Main()System.FormatException: Input string was not in a correct format.
at System.Number.ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type) at System.Number.ParseDecimal(ReadOnlySpan`1 value, NumberStyles styles, NumberFormatInfo info) at System.Decimal.Parse(String s) at Program.Main()
这个问题解释了如何修复它 for decimal.Parse
(Parse a Number from Exponential Notation) 但是我这个通用方法用于从许多地方的 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
and Decimal.TryParse
使用的默认样式是这样的
[ws][sign][digits,]digits[.fractional-digits][ws]
不允许指数。如果您阅读 Parse's documentation,您会看到完整的数字格式是
[ws][$][sign][digits,]digits[.fractional-digits][e[sign]digits][ws]
哪里
e: The 'e' or 'E' character, which indicates that the value is represented in exponential notation. The s parameter can represent a number in exponential notation if
style
includes theNumberStyles.AllowExponent
flag.
这意味着您需要像上面那样使用 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);