如何在不知道类型的情况下转换泛型类型 [英] How to cast a generic type without knowing the type
问题描述
我试图在运行时创建一个通用对象.到目前为止,我已经能够创建它,但是我不知道如何投射它.我拥有的是枚举对象,我想生成一个EnumMapper,它将枚举值转换为自定义字符串以映射到旧数据库.
I am trying to create a generic object in runtime. So far I have been able to create it but I can't figure out how to cast it. What I have is the enum object and I want to generate the EnumMapper that converts the enum value to custom string to map to a legacy database.
Type enumType = myEnum.GetType();
Type enumMapperType = typeof(EnumMapper<>)
.GetGenericTypeDefinition().MakeGenericType(enumType);
var mapper = Activator.CreateInstance(enumMapperType); // OK
EnumMapper<> mapper = (EnumMapper<>) Activator.CreateInstance(enumMapperType); // Error
当我在调试器中检查对象时,它是按预期的方式创建的,但是如何转换它以便可以使用呢?
When I inspect the object in the debugger it is create as I expect, but how can I cast it so I can use it?
课程:
public class EnumMapper<T> : IEnumMapper<T>
界面:
public interface IEnumMapper<T>
{
T EnumValue(string value);
bool HasEnumValue(string stringValue);
bool HasStringValue(T enumValue);
string StringValue(T enumValue);
}
Error 2 ; expected \EnumMapperTest.cs 36
Error 4 ; expected \EnumMapperTest.cs 36
Error 1 Invalid expression term '>' \EnumMapperTest.cs 36
Error 3 Invalid expression term '>' \EnumMapperTest.cs 36
Error 34 Only assignment, call, increment, decrement, and new object expressions can be used as a statement \EnumMapperTest.cs 36
Error 36 The name 'mapper' does not exist in the current context \EnumMapperTest.cs 36
Error 35 Using the generic type 'EnumMapper<T>' requires 1 type arguments \EnumMapperTest.cs 36
Error 37 Using the generic type 'EnumMapper<T>' requires 1 type arguments \EnumMapperTest.cs 36
推荐答案
据我所知,您所需的确切内容在C#中是不可能的.基本上,您需要根据常规非泛型参数的值(即,如果参数为 typeof(Enum1)
)与结果相比,方法具有不同的类型或返回的变量变量是 EnumMapper< Enum1>
,如果参数是 typeof(Enum2)
,则结果变量是 EnumMapper< Enum2>
.
As far as I know, the exact thing you need is not possible in C#. Basically, you need for a method to have different types or the returned variable, based on the value of a regular, non-generic, parameter, i.e. if the parameter is typeof(Enum1)
, than the result variable is EnumMapper<Enum1>
and if the parameter is typeof(Enum2)
, than the result variable is EnumMapper<Enum2>
.
您可以使用泛型参数来执行此操作,但是,由于泛型全部与编译时信息有关,并且仅在运行时具有该值,因此在这种情况下不能使用它们.
You can do this with generic parameters, however, since generics is all about compile-time information, and you only have the value at runtime, they cannot be used in this case.
您可以做的(以及我已经做的)是使用动态代码来解决此问题,请注意尽快进入静态类型的土地(动态确实具有传染性,有人说像微笑,有人说像病毒)
What you can do (and what I have done) is to use dynamic code to work around this problem, being careful to go into statically-typed land as soon as possible (dynamic is really contagious, some say like a smile, some say like a virus):
public dynamic GetMapperObject(Type enumType)
{
Type enumMapperType = typeof(EnumMapper<>)
.GetGenericTypeDefinition()
.MakeGenericType(enumType);
var mapper = Activator.CreateInstance(enumMapperType);
return mapper;
}
调用代码如下:
var mapper = GetMapperObject(enumType);
//dynamic call, bind the resut to a statically typed variable
bool result = mapper.HasEnumValue("SomeStringValue")
(旧答案,只是向问题添加了另一种间接访问级别:))
(old answer, just adds another level of indirection to the problem :) )
您可以将所有内容包装在通用方法中,如下所示:
You could wrap all that in a generic method, something like this:
public EnumMapper<T> GetMapperObject<T>()
{
Type enumType = typeof(T);
Type enumMapperType = typeof(EnumMapper<>)
.GetGenericTypeDefinition()
.MakeGenericType(enumType);
var mapper = Activator.CreateInstance(enumMapperType);
return mapper as EnumMapper<T>;
}
并使用
var mapper = GetMapperObject<EnumMapperTestEnum>();
但是,如果枚举只有一个值,则可以使用类型推断,例如:
However, if you only have a single value for the enum, you can use type inference, something like:
//everything is the same, just different signature
public EnumMapper<T> GetMapperByExample<T>(T item)
{
Type enumType = typeof(T);
Type enumMapperType = typeof(EnumMapper<>)
.GetGenericTypeDefinition()
.MakeGenericType(enumType);
var mapper = Activator.CreateInstance(enumMapperType); // OK
return mapper as EnumMapper<T>;
}
并使用类型推断对其进行调用
and call it with type inference
var mapper = GetMapperByExample(EnumMapperTestEnum.SomeValue);
这篇关于如何在不知道类型的情况下转换泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!