Generics in C#, using type of a variable as parame

2019-01-01 05:32发布

This question already has an answer here:

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.

4条回答
还给你的自由
2楼-- · 2019-01-01 05:59

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.

查看更多
与君花间醉酒
3楼-- · 2019-01-01 06:09

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.

查看更多
残风、尘缘若梦
4楼-- · 2019-01-01 06:14

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.

查看更多
旧人旧事旧时光
5楼-- · 2019-01-01 06:15

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);
查看更多
登录 后发表回答