Установка родового типа во время выполнения

У меня есть класс

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);
        }