149

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.

5
  • you can't use a generic that way (first example) Commented Jan 21, 2010 at 8:38
  • Also: why would a DoesEntityExist() method require a transaction parameter? Commented Jan 21, 2010 at 8:38
  • 4
    Similar question at stackoverflow.com/questions/687363/… and stackoverflow.com/questions/2078914/c-dynamic-generic-type Commented Jan 21, 2010 at 8:48
  • @MitchWheat, maybe he want to check if the entity exists in a database. Commented Sep 10, 2012 at 16:08
  • 1
    This 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. Commented Nov 25, 2015 at 13:13

4 Answers 4

196

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.

Sign up to request clarification or add additional context in comments.

7 Comments

I think that the most important thing in this answer is ick. That and compile-time type safety.
@Mitch: The trouble is that sometimes it's necessary. It's ugly and should be avoided wherever possible... but occasionally you need it.
@MoslemBenDhaou: No, because there's no instance to use for type inference here.
@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.
@JonSkeet: here is a new question : stackoverflow.com/questions/16491618/… (Thank you!)
|
43

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

3 Comments

this is great! are there any downsides? seems like more elegant solution to the original question than using reflection??
It 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.
I 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 do Sort(input)!
14

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.

Comments

6

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.