How to turn a Type instance into a generic type argument
Asked Answered
P

5

10

I basically have something like this:

void Foo(Type ty)
{
    var result = serializer.Deserialize<ty>(inputContent);
}

Foo(typeof(Person));

The Deserialize<ty> doesn't work because it expects Deserialize<Person> instead. How do I work around this?

I'd also like to understand how generics work and why it won't accept ty which is typeof(Person).

EDIT: I ought to have mentioned that this is a contrived example. I cannot actually change the signature of the function because it implements an interface.

EDIT: serializer is a JavascriptSerializer and implemented as an action filter here. It is called thusly:

[JsonFilter(Param="test", JsonDataType=typeof(Person))]

Solution

Based on Marc and Anton's answers:

var result = typeof(JavaScriptSerializer).GetMethod("Deserialize")
                 .MakeGenericMethod(JsonDataType)
                 .Invoke(serializer, new object[] { inputContent });
Prefecture answered 13/5, 2009 at 8:0 Comment(1)
Surely it would be easier to change the interface (or add a new overload of Foo) than to look for a work round when the correct code is so simple?Reciprocal
A
6

If ty is known at compile-time, why don't just

void Foo<T>()
{
    var result = serializer.Deserialize<T>(inputContext);
}

Otherwise,

MethodInfo genericDeserializeMethod = serializer.GetType().GetMethod("Deserialize");
MethodInfo closedDeserializeMethod = genericDeserializeMethod.MakeGenericMethod(ty);
closedDeserializeMethod.Invoke(serializer, new object[] { inputContext });
Absquatulate answered 13/5, 2009 at 8:6 Comment(0)
B
7

Which serializer is that? If you only know the Type at runtime (not compile time), and it doesn't have a non-generic API, then you might have to use MakeGenericMethod:

void Foo(Type ty)
{
    object result = typeof(ContainingClass).GetMethod("Bar").
        .MakeGenericMethod(ty).Invoke(null, new object[] {inputContent});
}
public static T Bar<T>(SomeType inputContent) {
    return serializer.Deserialize<T>(inputContent);
}
Born answered 13/5, 2009 at 8:5 Comment(3)
I'm not sure what ContainingClass is here and why pass in "Bar"?Prefecture
ContainingClass is the class that has the Bar method, and "Bar" is used to find the Bar method by name. You could also (per Anton's answer) go straight to the "Serialize" method on the serializer.Born
Got it now. This works: var result = typeof(JavaScriptSerializer).GetMethod("Deserialize") .MakeGenericMethod(JsonDataType).Invoke(serializer, new object[] { inputContent }); calling Invoke(null, ...) throws a TargetException ("non-static method required")Prefecture
A
6

If ty is known at compile-time, why don't just

void Foo<T>()
{
    var result = serializer.Deserialize<T>(inputContext);
}

Otherwise,

MethodInfo genericDeserializeMethod = serializer.GetType().GetMethod("Deserialize");
MethodInfo closedDeserializeMethod = genericDeserializeMethod.MakeGenericMethod(ty);
closedDeserializeMethod.Invoke(serializer, new object[] { inputContext });
Absquatulate answered 13/5, 2009 at 8:6 Comment(0)
R
2

Use

void Foo<T>(){ var result = serializer.Deserialize<T>(inputContent); }

With the following call

Foo<Person>();
Reciprocal answered 13/5, 2009 at 8:4 Comment(0)
O
1

In this case, just do this:

void Foo<ty>()
{
    var result = serializer.Deserialize<ty>(inputContent);
}

Foo<Person>();

Otherwise, you need to call the generic method late-bound, since you have to get the correct generic method for it first (it is not known at compile time). Have a look at the MethodInfo.MakeGenericMethod method.

Or answered 13/5, 2009 at 8:6 Comment(0)
S
1

Like Lucero said,

void Foo<ty>()
{
    var result = serializer.Deserialize<ty>(inputContent);
}

Foo<Person>();

typeof(Person) is not the same thing as Person. Person is a compile-time type, whereas typeof(Person) is an expression that returns a Type instance representing the runtime type information of Person.

Strickland answered 13/5, 2009 at 8:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.