49

I have a class

public class A<T>
{
   public static string B(T obj)
   {
       return TransformThisObjectToAString(obj);
   }
}

The use of string above is purely exemplary. I can call the static function like this just fine on a known/specified type:

string s= A<KnownType>.B(objectOfKnownType);

How do I make this call, if I don't know T beforehand, rather I have a variable of type Type that holds the type. If I do this:

Type t= typeof(string);
string s= A<t>.B(someStringObject);

I get this compiler error:

Cannot implicitly convert type 't' to 'object'
Venkat Peri
  • 1,744
  • 3
  • 16
  • 20
  • Close [c-sharp-dynamic-generic-type](http://stackoverflow.com/questions/2078914/c-sharp-dynamic-generic-type) – nawfal Jan 17 '14 at 08:52

6 Answers6

47

You can't do this directly, but you can use reflection to provide a type parameter of a class at run-time. I haven't tested this, but something like this should work:

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

Of course, the question is if this is really what you need - If you don't know anything about the object given as an argument, you could as well write the whole code just using object. However, I can imagine some scenarios where this would be useful, so I guess you can try using this.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Ooh, I didn't realize you could pass `A<>` to `typeof()`. Your code is definitely cleaner than mine. Good job. – Dathan Apr 09 '10 at 02:58
  • I don't really like the fact that you can write `A<>` in C# as it ins't _really_ a type. It's kind of a weird thing. Anyway, I guess it's sometimes useful :-). – Tomas Petricek Apr 09 '10 at 03:02
  • Writing `A<>`, and stuff like `Outer<,>.Inner<,,,>` is useful for a `typeof` "argument", but it is a good thing it is not allowed in other contexts since you are right it is not a C# type. – Jeppe Stig Nielsen Mar 10 '18 at 12:41
  • `A<>` is an incomplete type. I've used a construct like this in the context of a factory, where I was looking for types that inherited from a generic base using the CRTP. I would load all of the types from an assembly, see if I could instantiate the generic base on the type, then see if the type inherited from the instantiation. If it did, it was one of the types my factory could create. – Craig Sep 20 '18 at 13:29
16

There's absolutely support for this in the framework and the CLR - just not gracefully in C#. You can accomplish what I think you want, though, with the help of a helper method:

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);
    }
Dathan
  • 7,266
  • 3
  • 27
  • 46
15

You can't. Generic type identifiers have to be known at compile time.

edit

as of other posts, it appears to be possible by dynamicly generating the method and invoking it - which has dangers of course. See Thomas' and Dathan's posts for more inforation.

Femaref
  • 60,705
  • 7
  • 138
  • 176
  • I guess I misread the question. Can't really add anything else beyond what you've said. – ChaosPandion Apr 09 '10 at 02:35
  • 7
    It would be more accurate to say that there's no statically-typed way to do it; or perhaps no idiomatic way. But as Tomas's and my responses show, the method can be resolved dynamically and called at runtime with arbitrary arguments. – Dathan Apr 09 '10 at 04:18
4

You can't. But you've asked the wrong question for the case provided. In this case (as in 99% of cases) all you actually need is a type constraint.

Try:

public class A<T> where T : object

or, if T is a known class, a subclass, or an interface then it would be better to use

public class A<T> where T : YourAbstractClass

Other type constraints also exist. More details: http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx

As a general note, when learning a new language, you often have to think broadly about what you want to achieve, not specifically finding what you want to do. This is much like real-world verbal languages. It's the difference between learning German by reading a dictionary and forcing the words into English syntax, or learning the syntax and picking up the words. Yes, a German speaker will understand someone who is speaking out of a dictionary, but the WTF per sentence count will be much higher.

alirobe
  • 846
  • 6
  • 11
3

I created this helper method based on some of the answers here + else where on the web.

usage:

InvokeGenericMethodWithRuntimeGenericArguments( MyMethodWithGenericType<IType>, new[] {MyRuntimeGenericType}, null);

method:

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);
        }
Obiwan
  • 59
  • 4
1

Trying to substitute type parameter at runtime will defeat the whole purpose of type saftey , which is enforced by C# compiler.C# compiler make sures that type parameter are specified at compile time and there is no ambiguity on type arguments at runtime.I doubt you can substitue type parameter at runtime in Generic Type.Specifying type argument of type "Type" is almost like having an unbound generic type.

Pawan Mishra
  • 7,212
  • 5
  • 29
  • 39