如何在不知道类型的情况下强制转换泛型类型

unc*_*all 5 c# generics

我正在尝试在运行时创建一个通用对象。到目前为止,我已经能够创建它,但我不知道如何投射它。我拥有的是枚举对象,我想生成将枚举值转换为自定义字符串以映射到旧数据库的 EnumMapper。

Type enumType = myEnum.GetType();
Type enumMapperType = typeof(EnumMapper<>)
                      .GetGenericTypeDefinition().MakeGenericType(enumType);
var mapper = Activator.CreateInstance(enumMapperType); // OK
EnumMapper<> mapper = (EnumMapper<>) Activator.CreateInstance(enumMapperType); // Error
Run Code Online (Sandbox Code Playgroud)

当我在调试器中检查对象时,它是按我的预期创建的,但是我如何投射它以便我可以使用它?

班上:

public class EnumMapper<T> : IEnumMapper<T>
Run Code Online (Sandbox Code Playgroud)

界面:

public interface IEnumMapper<T>
{
    T EnumValue(string value);

    bool HasEnumValue(string stringValue);

    bool HasStringValue(T enumValue);

    string StringValue(T enumValue);
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

SWe*_*eko 2

据我所知,您所需要的东西在 C# 中是不可能的。基本上,您需要一个方法具有不同的类型或返回的变量,基于常规、非泛型参数的值,即,如果参数是 ,则结果typeof(Enum1)变量是,如果EnumMapper<Enum1>参数是typeof(Enum2),则结果变量是变量是EnumMapper<Enum2>.

您可以使用泛型参数来做到这一点,但是,由于泛型都是关于编译时信息的,并且您只有在运行时才具有值,因此在这种情况下不能使用它们。

你能做的(以及我所做的)是使用动态代码来解决这个问题,小心地尽快进入静态类型的领域(动态确实具有传染性,有人说像微笑,有人说像病毒):

public dynamic GetMapperObject(Type enumType)
{
  Type enumMapperType = typeof(EnumMapper<>)
                           .GetGenericTypeDefinition()
                           .MakeGenericType(enumType);
  var mapper = Activator.CreateInstance(enumMapperType);
  return mapper;
}
Run Code Online (Sandbox Code Playgroud)

调用代码如下:

var mapper = GetMapperObject(enumType);
//dynamic call, bind the resut to a statically typed variable
bool result = mapper.HasEnumValue("SomeStringValue") 
Run Code Online (Sandbox Code Playgroud)

(旧答案,只是为问题增加了另一个间接级别:))

您可以将所有这些包装在一个通用方法中,如下所示:

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>;
}
Run Code Online (Sandbox Code Playgroud)

并调用它

var mapper = GetMapperObject<EnumMapperTestEnum>();
Run Code Online (Sandbox Code Playgroud)

但是,如果枚举只有一个值,则可以使用类型推断,例如:

//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>;
}
Run Code Online (Sandbox Code Playgroud)

并通过类型推断来调用它

var mapper = GetMapperByExample(EnumMapperTestEnum.SomeValue); 
Run Code Online (Sandbox Code Playgroud)

  • 问题是我没有 T,我得到一个枚举,然后想为这个枚举创建一个枚举映射器...... (2认同)