C#中的泛型,使用变量的类型作为参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2107845/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generics in C#, using type of a variable as parameter
提问by Germstorm
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?)
找不到类型或命名空间名称“t”(您是否缺少 using 指令或程序集引用?)
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.
工作完美,但我不想使用 if 指令每次都使用单独的类型名称调用该方法。
采纳答案by Jon Skeet
The point about generics is to give compile-timetype safety - which means that types need to be known at compile-time.
关于泛型的要点是提供编译时类型安全——这意味着需要在编译时知道类型。
You cancall 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 callingmethod 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.
如果你能给我们更多关于你在做什么的信息,那会有所帮助。有时你可能需要像上面一样使用反射,但是如果你选择了正确的点来做,你可以确保你只需要做一次,并且让该点以下的所有东西都以正常方式使用类型参数。
回答by Rob Levine
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.
正如其他答案中提到的那样,另一种选择是使用反射从开放类型创建封闭类型,尽管在我所说的极端利基场景之外的任何情况下都可能建议这样做。
回答by kosto
I'm not sure whether I understand your question correctly, but you can write your code in this way:
我不确定我是否正确理解您的问题,但您可以这样编写代码:
bool DoesEntityExist<T>(T instance, ....)
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.
这样你就不需要显式地编写类型,框架会自动从实例中取代类型。
回答by Joe Lloyd
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);