Ответ 1
Если у вас есть известный набор типов для преобразования, вы можете сделать серию if/elseif/elseif/else
(или switch/case
в имени типа), чтобы по существу распространить ее на специализированные методы синтаксического анализа. Это должно быть довольно быстро. Это описано в @Fabio answer.
Если у вас все еще есть проблемы с производительностью, вы также можете создать таблицу поиска, которая позволит вам добавить новые методы парсинга, как вам необходимо их поддерживать:
Учитывая некоторые основные синтаксические разборки:
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;
}
}
Затем вы можете настроить помощник преобразования, который выполняет поиск, и вызывает соответствующий синтаксический анализатор:
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));
}
}
Тогда использование может выглядеть следующим образом:
//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
}
Вероятно, возможно, что генераторы расширены, чтобы избежать object
бокса и типа литья, но по мере того, как это происходит, это отлично работает; возможно, только оптимизировать этот аспект, если у вас есть измеримая производительность.
EDIT: вы можете обновить метод DataConversion.Convert
, чтобы, если у него нет зарегистрированного зарегистрированного конвертера, он может вернуться к вашему методу TypeConverter
или выбросить соответствующее исключение. Это зависит от вас, если вы хотите иметь уловки или просто иметь предопределенный набор поддерживаемых типов и избегать повторного использования try/catch
. Как бы то ни было, код обновлен, чтобы выбросить NotSupportedException
с сообщением о неподдерживаемом типе. Не стесняйтесь настраивать, поскольку это имеет смысл. Производительность мудрая, может быть, имеет смысл делать ловушки, поскольку, возможно, их будет меньше и далеко друг от друга, как только вы укажете специализированные парсеры для наиболее часто используемых типов.