Установка родового типа во время выполнения
У меня есть класс
public class A<T>
{
public static string B(T obj)
{
return TransformThisObjectToAString(obj);
}
}
Использование строки выше является чисто образцовым. Я могу вызвать статическую функцию как это просто отлично на известном/указанном типе:
string s= A<KnownType>.B(objectOfKnownType);
Как мне сделать этот вызов, если я не знаю T заранее, скорее у меня есть переменная типа Тип, которая содержит тип. Если я это сделаю:
Type t= typeof(string);
string s= A<t>.B(someStringObject);
Я получаю эту ошибку компилятора:
Cannot implicitly convert type 't' to 'object'
Ответы
Ответ 1
Вы не можете. Идентификаторы общего типа должны быть известны во время компиляции.
изменить
по сравнению с другими постами, это, по-видимому, возможно путем динамического создания метода и его вызова - что, конечно, имеет опасности. См. Сообщения Томаса и Датана для более подробной информации.
Ответ 2
Вы не можете сделать это напрямую, но вы можете использовать отражение для предоставления параметра типа класса во время выполнения. Я не тестировал это, но что-то вроде этого должно работать:
// We want to do something like this:
// object o = "Hello"
// Type t = o.GetType();
//
// This is pseudo-code only:
// string s = A<t>.B(o);
string InvokeA(object o) {
// Specify the type parameter of the A<> type
Type genericType = typeof(A<>).MakeGenericType(new Type[] { o.GetType() });
// Get the 'B' method and invoke it:
object res = genericType.GetMethod("B").Invoke(new object[] { o });
// Convert the result to string & return it
return (string)res;
}
Конечно, вопрос в том, действительно ли это то, что вам нужно. Если вы ничего не знаете об объекте, указанном в качестве аргумента, вы также можете написать весь код, просто используя объект. Однако я могу представить некоторые сценарии, где это было бы полезно, поэтому я думаю, вы можете попробовать использовать это.
Ответ 3
Там абсолютно поддерживается это в рамках и CLR - просто не изящно в С#. Вы можете выполнить то, что, я думаю, вы хотите, однако, с помощью вспомогательного метода:
public class A<T>
{
public static string B(T obj)
{
return obj.ToString();
}
}
public class MyClass
{
public static void DoExample()
{
Console.WriteLine(ExecuteB("Hi"));
Console.WriteLine(ExecuteB(DateTime.Now));
}
public static object ExecuteB(object arg)
{
Type arg_type = arg.GetType();
Type class_type = typeof(MyClass);
MethodInfo mi = class_type.GetMethod("ExecuteBGeneric", BindingFlags.Static | BindingFlags.Public);
MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { arg_type });
return mi2.Invoke(null, new object[] { arg });
}
public static object ExecuteBGeneric<T>(T arg)
{
return A<T>.B(arg);
}
Ответ 4
Вы не можете. Но вы задали неправильный вопрос по предоставленному делу. В этом случае (как в 99% случаев) все, что вам действительно нужно, это ограничение типа.
Try:
public class A<T> where T : object
или, если T - известный класс, подкласс или интерфейс, то лучше использовать
public class A<T> where T : YourAbstractClass
Существуют и другие ограничения типа. Подробнее: http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx
В общем, при изучении нового языка вам часто приходится много думать о том, чего вы хотите достичь, а не конкретно о том, что вы хотите делать. Это очень похоже на вербальные языки мира. Это разница между изучением немецкого языка, чтением словаря и принуждением слов в синтаксисе английского языка, или изучением синтаксиса и подбором слов. Да, немецкий спикер поймет того, кто говорит из словаря, но количество WTF за число будет намного выше.
Ответ 5
Попытка подменить параметр типа во время выполнения приведет к победе над целым назначением типа saftey, который принудительно выполняется компилятором С# compiler.С#, который гарантирует, что параметр типа указывается во время компиляции, и не существует двусмысленности в аргументах типа во время выполнения. я сомните, что вы можете подставить параметр типа во время выполнения в Generic Type.Specifying аргумент типа типа Type "почти похож на несвязанный общий тип.
Ответ 6
Я создал этот вспомогательный метод, основанный на некоторых ответах здесь +, где в Интернете.
использование:
InvokeGenericMethodWithRuntimeGenericArguments( MyMethodWithGenericType<IType>, new[] {MyRuntimeGenericType}, null);
метод:
public static object InvokeGenericMethodWithRuntimeGenericArguments(Action methodDelegate, Type[] runtimeGenericArguments, params object[] parameters)
{
if (parameters == null)
{
parameters = new object[0];
}
if (runtimeGenericArguments == null)
{
runtimeGenericArguments = new Type[0];
}
var myMethod = methodDelegate.Target.GetType()
.GetMethods()
.Where(m => m.Name == methodDelegate.Method.Name)
.Select(m => new
{
Method = m,
Params = m.GetParameters(),
Args = m.GetGenericArguments()
})
.Where(x => x.Params.Length == parameters.Length
&& x.Args.Length == runtimeGenericArguments.Length
)
.Select(x => x.Method)
.First().MakeGenericMethod(runtimeGenericArguments);
return myMethod.Invoke(methodDelegate.Target, parameters);
}