Dav*_*New 18 .net c# performance parsing exception
我正在将CSV文件解析为具有强类型属性的对象列表.这涉及从文件中的每个字符串值解析到一个IConvertible
类型(int
,decimal
,double
,DateTime
使用等)TypeDescriptor
.
我正在使用a try catch
来处理解析失败时的情况.然后记录发生此异常的位置和原因的确切细节以供进一步调查.下面是实际解析代码:
try
{
parsedValue = TypeDescriptor.GetConverter(type).ConvertFromString(dataValue);
}
catch (Exception ex)
{
// Log failure
}
Run Code Online (Sandbox Code Playgroud)
问题:
成功解析值后,过程很快.在解析具有大量无效数据的数据时,该过程可能会慢几千倍(由于捕获异常).
我一直在测试这个解析DateTime
.这些是性能数据:
这慢了4500多倍.
题:
我是否可以检查是否可以成功解析字符串值而无需使用我昂贵的try catch
方法?或许还有另一种方法我应该这样做?
编辑:我需要使用TypeDescriptor
(而不是DateTime.TryParse
)因为类型是在运行时确定的.
Chr*_*air 13
如果您有一组已知的要转换的类型,您可以执行一系列if/elseif/elseif/else
(或switch/case
类型名称)以将其实际分发到专门的解析方法.这应该很快.这就像@Fabio的回答中所描述的那样.
如果仍然存在性能问题,还可以创建一个查找表,以便在需要时添加新的解析方法来支持它们:
给出一些基本的解析包装器:
public delegate bool TryParseMethod<T>(string input, out T value);
public interface ITryParser
{
bool TryParse(string input, out object value);
}
public class TryParser<T> : ITryParser
{
private TryParseMethod<T> ParsingMethod;
public TryParser(TryParseMethod<T> parsingMethod)
{
this.ParsingMethod = parsingMethod;
}
public bool TryParse(string input, out object value)
{
T parsedOutput;
bool success = ParsingMethod(input, out parsedOutput);
value = parsedOutput;
return success;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以设置转换帮助程序,它执行查找并调用相应的解析器:
public static class DataConversion
{
private static Dictionary<Type, ITryParser> Parsers;
static DataConversion()
{
Parsers = new Dictionary<Type, ITryParser>();
AddParser<DateTime>(DateTime.TryParse);
AddParser<int>(Int32.TryParse);
AddParser<double>(Double.TryParse);
AddParser<decimal>(Decimal.TryParse);
AddParser<string>((string input, out string value) => {value = input; return true;});
}
public static void AddParser<T>(TryParseMethod<T> parseMethod)
{
Parsers.Add(typeof(T), new TryParser<T>(parseMethod));
}
public static bool Convert<T>(string input, out T value)
{
object parseResult;
bool success = Convert(typeof(T), input, out parseResult);
if (success)
value = (T)parseResult;
else
value = default(T);
return success;
}
public static bool Convert(Type type, string input, out object value)
{
ITryParser parser;
if (Parsers.TryGetValue(type, out parser))
return parser.TryParse(input, out value);
else
throw new NotSupportedException(String.Format("The specified type \"{0}\" is not supported.", type.FullName));
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用可能是这样的:
//for a known type at compile time
int value;
if (!DataConversion.Convert<int>("3", out value))
{
//log failure
}
//or for unknown type at compile time:
object value;
if (!DataConversion.Convert(myType, dataValue, out value))
{
//log failure
}
Run Code Online (Sandbox Code Playgroud)
这可能会扩展泛型,以避免object
拳击和类型铸造,但它现在的工作正常; 如果你有可衡量的表现,也许只会优化这个方面.
编辑:您可以更新DataConversion.Convert
方法,以便如果它没有注册指定的转换器,它可以回退到您的TypeConverter
方法或抛出适当的异常.如果你想拥有一个全能或只是拥有你预先定义的一组受支持的类型,并且避免让你try/catch
重复一遍,这取决于你.目前,代码已更新为抛出NotSupportedException
一条消息,指示不支持的类型.随意调整,因为它是有道理的.性能方面,也许有意义的做全能,因为一旦为最常用的类型指定专用解析器,这些可能会更少和更远.
如果您知道要尝试解析的类型,请使用TryParse方法:
String value;
Int32 parsedValue;
if (Int32.TryParse(value, parsedValue) == True)
// actions if parsed ok
else
// actions if not parsed
Run Code Online (Sandbox Code Playgroud)
其他类型相同
Decimal.TryParse(value, parsedValue)
Double.TryParse(value, parsedValue)
DateTime.TryParse(value, parsedValue)
Run Code Online (Sandbox Code Playgroud)
或者您可以使用下一个解决方法:
为每个具有相同名称但不同签名的类型创建一个解析方法(在其中包装TryParse):
Private bool TryParsing(String value, out Int32 parsedValue)
{
Return Int32.TryParse(value, parsedValue)
}
Private bool TryParsing(String value, out Double parsedValue)
{
Return Double.TryParse(value, parsedValue)
}
Private bool TryParsing(String value, out Decimal parsedValue)
{
Return Decimal.TryParse(value, parsedValue)
}
Private bool TryParsing(String value, out DateTime parsedValue)
{
Return DateTime.TryParse(value, parsedValue)
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用TryParsing
你的类型的方法
归档时间: |
|
查看次数: |
8798 次 |
最近记录: |