Generics in C#, using type of a variable as parameter
Solution 1
The point about generics is to give compile-time type safety - which means that types need to be known at compile-time.
You can call generic methods with types only known at execution time, but you have to use reflection:
// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
.MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });
Ick.
Can you make your calling method generic instead, and pass in your type parameter as the type argument, pushing the decision one level higher up the stack?
If you could give us more information about what you're doing, that would help. Sometimes you may need to use reflection as above, but if you pick the right point to do it, you can make sure you only need to do it once, and let everything below that point use the type parameter in a normal way.
Solution 2
One way to get around this is to use implicit casting:
bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;
calling it like so:
DoesEntityExist(entity, entityGuid, transaction);
Going a step further, you can turn it into an extension method (it will need to be declared in a static class):
static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;
calling as so:
entity.DoesEntityExist(entityGuid, transaction);
Solution 3
I'm not sure whether I understand your question correctly, but you can write your code in this way:
bool DoesEntityExist<T>(T instance, ....)
You can call the method in following fashion:
DoesEntityExist(myTypeInstance, ...)
This way you don't need to explicitly write the type, the framework will overtake the type automatically from the instance.
Solution 4
You can't use it in the way you describe. The point about generic types, is that although you may not know them at "coding time", the compiler needs to be able to resolve them at compile time. Why? Because under the hood, the compiler will go away and create a new type (sometimes called a closed generic type) for each different usage of the "open" generic type.
In other words, after compilation,
DoesEntityExist<int>
is a different type to
DoesEntityExist<string>
This is how the compiler is able to enfore compile-time type safety.
For the scenario you describe, you should pass the type as an argument that can be examined at run time.
The other option, as mentioned in other answers, is that of using reflection to create the closed type from the open type, although this is probably recommended in anything other than extreme niche scenarios I'd say.
Stefano
I'm a software developer. I like web comics, TV-shows, movies, PC games and books. Read my blog if you want to find out more about me.
Updated on July 08, 2022Comments
-
Stefano almost 2 years
I have a generic method
bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;
How do I use the method in the following way:
Type t = entity.GetType(); DoesEntityExist<t>(entityGuid, transaction);
I keep receiving the foollowing compile error:
The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)
DoesEntityExist<MyType>(entityGuid, transaction);
works perfectly but I do not want to use an if directive to call the method with a separate type name every time.
-
Mitch Wheat over 14 yearsyou can't use a generic that way (first example)
-
Mitch Wheat over 14 yearsAlso: why would a DoesEntityExist() method require a transaction parameter?
-
Jonas Elfström over 14 yearsSimilar question at stackoverflow.com/questions/687363/… and stackoverflow.com/questions/2078914/c-dynamic-generic-type
-
Guillermo Gutiérrez over 11 years@MitchWheat, maybe he want to check if the entity exists in a database.
-
G.Y over 8 yearsThis is not a duplicate question. it is a different aspect of the other question - answers in the other question do not qualify as answers to this question.
-
-
Fredrik Mörk over 14 yearsI think that the most important thing in this answer is ick. That and compile-time type safety.
-
Jon Skeet over 14 years@Mitch: The trouble is that sometimes it's necessary. It's ugly and should be avoided wherever possible... but occasionally you need it.
-
Moslem Ben Dhaou about 11 years@JonSkeet: is there a way to adapt this using the
dynamic
keyword? -
Jon Skeet about 11 years@MoslemBenDhaou: No, because there's no instance to use for type inference here.
-
Moslem Ben Dhaou about 11 years@JonSkeet: well here is my situation, a bit similar: I have an instance of an object passed as an interface variable to a method calling a generic API method:
public static Boolean PurgeDataObject(this IDataObject dataObject, Guid uid) { return DataProvider.DeleteDataObject<T>(uid, DataProvider.GetConnection()); }
. I am missing how to get the concrete type of dataObject and passed it as T. -
Jon Skeet about 11 years@MoslemBenDhaou: Well you could go via an intermediate generic method using
dynamic
to infer the type. If that's not enough information, ask a new question - it's sufficiently different from this one that pursuing it in comments isn't ideal. -
Moslem Ben Dhaou about 11 years@JonSkeet: here is a new question : stackoverflow.com/questions/16491618/… (Thank you!)
-
Sonic Soul over 10 yearsthis is great! are there any downsides? seems like more elegant solution to the original question than using reflection??
-
Tom Bowers over 10 yearsThere's an error in the above code.
Type
doesn't have anInvoke()
method. It should be called on themethod
variable instead. -
zionpi about 10 yearsAny hint on refactor method to make existing method to accept generic type ,dear @JonSkeet
-
Jon Skeet about 10 years@zionpi: I don't follow exactly what you mean, but it sounds like you should probably ask a new question with examples.
-
Grigory about 9 yearsIt only works if declared type is enough. What if entity is declared as object ? The solution of JonSkeet creates generic version where T is real type, not the declared one.
-
Bret about 7 yearsI didn't know that using the T constraint allowed you to bypass the type parameter when you call the method. I was trying to figure out something like
Sort<typeof(input)>(input)
when I can just doSort(input)
!