Текущее решение
Текущее решение, которое я использую на работе, основано на динамической диспетчеризации, то есть на динамическом ключевом слове, как определено в C # 4.0.
Код похож на (из памяти):
public class Parser
{
static public void TryParse<T>(string p_input, out T p_output)
{
// Because m_p is dynamic, the function to be called will
// be resolved at runtime, after T is known...
m_p.DoTryParse(p_input, out p_output) ;
}
// The dynamic keyword means every function called through
// m_p will be resolved at runtime, at the moment of the call
private dynamic m_p = new Parser() ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
private void DoTryParse(string p_input, out double p_output)
{ /* Do something and return the right value */ }
private void DoTryParse(string p_input, out int p_output)
{ /* Do something and return the right value */ }
// etc.
private void DoTryParse<T>(string p_input, out T p_output)
{
// fallback method... There are no dedicated method for T,
// so p_output becomes the default value for T
p_output = default(T) ;
}
}
Элегантная часть состоит в том, что она не может завершиться ошибкой (функция отката будет вызвана, если не найдена ни одна из них с лучшим совпадением сигнатур), и что она следует простому шаблону (перегрузитеfunction).
Конечно, реальный, производственный код несколько отличается и более сложен, потому что, имея только один публичный статический метод, я хочу:
- разобрать обассылочные объекты (классы) и объекты-значения (структуры)
- перечисления enum
- разбираемые типы, допускающие синтаксический анализ
- Я хочу предложить пользователю возможность получить из Parser возможность предложить свой собственныйперегрузки в дополнение к настройкам по умолчанию
Но я предполагаю, что использование динамического в текущем решении, в конце концов, то же самое, что и отражение, как в первоначальном ответениже.Изменяется только «нотация».
Заключение, у меня теперь есть следующий метод:
public class Parser
{
static public void TryParse<T>(string p_input, out T p_output)
{
// etc.
}
}
, который может анализировать что угодно, в том числе в ситуациях, когда T не известно во время компиляции (потому что код является общим).
Оригинальный ответ
Ответ Джейсона был прав насчет первого вопроса (об ошибках компилятора).Тем не менее, у меня не было решения моей проблемы (отправка из универсального метода в неуниверсальные методы в соответствии с универсальным типом времени выполнения T).
Я пытался ответ LukeH , но это не такt работа: универсальный метод вызывается всегда, несмотря ни на что ( даже при удалении квалификатора out
второго параметра ).
Ответ Мортена - этосамый разумный, который должен работать, но не использует отражения.
Итак, чтобы решить свою проблему, я использовал отражение.Для этого необходимо переписать универсальный метод TryParse:
public class MyType<T>
{
public void TryParse(string p_value)
{
T value = default(T);
// search for the method using reflection
System.Reflection.MethodInfo methodInfo = typeof(Parser).GetMethod
(
"TryParse",
new System.Type[] { typeof(string), typeof(T).MakeByRefType() }
);
if (methodInfo != null)
{
// the method does exist, so we can now call it
var parameters = new object[] { p_value, value };
methodInfo.Invoke(null, parameters);
value = (T)parameters[1];
}
else
{
// The method does not exist. Handle that case
}
}
}
У меня есть исходный код, если необходимо.