static object HandleEnumViaReflection(object e)
{
int x = (int) e + 1;
return Activator.CreateInstance(e.GetType(), x);
}
这不起作用——但它可以。事实上,如果在运行时找不到类型,我们可以创建它。
如果您必须使用反射或其他间接方式,那么您可以使用 ModuleBuilder 实例和 IEnumerable<KeyValuePair<string,int>> 定义自己的枚举。下面我们传入 IEnumerable 只是因为它简化了方法体。
static object HandleEnumViaOtherMeans(object e, List<KeyValuePair<string,int>> colors)
{
int x = (int) e + 1;
var arbitraryName = new AssemblyName(Guid.NewGuid().Replace("-", string.Empty));
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(arbitraryName, AssemblyBuilderAccess.Run);
var builder = assemblyBuilder.DefineDynamicModule(arbitraryName.Name);
var colorEnum = builder.DefineEnum("Color", TypeAttributes.Public, typeof(int));
foreach(var color in colors)
{
colorEnum.DefineLiteral(color.Key,color.Value);
}
var complete = colorEnum.CreateType();
return Enum.ToObject(complete, x);
}
这通常不是实现您的目的的好方法,但当事先不知道调色板时(即在设计或构建时),它会很有用。
但是,在这种情况下,大多数人会将类型生成提取到单独的静态方法中,这样我们就可以避免重建丢失的类型。
public class ColorHandler
{
static ColorHandler()
{
CurrentColors = new List<KeyValuePair<string,int>>();
}
public static List<KeyValuePair<string,int>> CurrentColors { get; set; }
private static Type _colorType;
public static Type ColorType => _colorType ?? (_colorType = DefineColor());
private static DefineColor()
{
var arbitraryName = new AssemblyName(Guid.NewGuid().Replace("-", string.Empty));
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(arbitraryName, AssemblyBuilderAccess.Run);
var builder = assemblyBuilder.DefineDynamicModule(arbitraryName.Name);
var colorEnum = builder.DefineEnum("Color", TypeAttributes.Public, typeof(int));
foreach(var color in CurrentColors)
{
colorEnum.DefineLiteral(color.Key,color.Value);
}
return colorEnum.CreateType();
}
public static object HandleEnum(object e)
{
int x = (int) e + 1;
return Enum.ToObject(ColorType, x);
}
}
现在我们几乎绕了一圈。特别是如果我们有一个泛型类,但仍想以不平凡的方式使用 Activator.CreateInstance()。
public class ColorConsumer<C> where C : struct
{
public C InstanceColor { get; set; }
public ColorConsumer(dynamic color)
{
InstanceColor = color;
}
//we can move the HandleEnum method here from ColorHandler
public object HandleEnum()
{
int x = (int) InstanceColor + 1;
return Enum.ToObject(typeof(C), x);
}
}
现在我们可以更新 ColorHandler 类了。
public class ColorHandler
{
static ColorHandler()
{
CurrentColors = new List<KeyValuePair<string,int>>();
}
private static List<KeyValuePair<string,int>> _current;
public static List<KeyValuePair<string,int>> CurrentColors
{
get
{
return _current;
}
set
{
if(value != _current && (null != _colorType))
{
_current = Value;
_colorType = DefineColor();
}
}
}
private static Type _colorType;
public static Type ColorType => _colorType ?? (_colorType = DefineColor());
private static DefineColor()
{
var arbitraryName = new AssemblyName(Guid.NewGuid().Replace("-", string.Empty));
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(arbitraryName, AssemblyBuilderAccess.Run);
var builder = assemblyBuilder.DefineDynamicModule(arbitraryName.Name);
var colorEnum = builder.DefineEnum("Color", TypeAttributes.Public, typeof(int));
foreach(var color in CurrentColors)
{
colorEnum.DefineLiteral(color.Key,color.Value);
}
return colorEnum.CreateType();
}
public static object HandleEnumViaReflection(object e)
{
var openType = typeof(ColorConsumer<>);
var typeToActivate = openType.MakeGenericType(new Type[]{ ColorType });
var consumer = Activator.CreateInstance(typeToActivate, new object[]{ e });
return consumer.HandleEnum();
}
}
现在我们有了通用参数和对 Activator.CreateInstance() 的调用。
QEF。
让我们看看如何称呼它。
var e = anInstanceOfSomeEnumeration;
ColorHandler.CurrentColors.Add(new KeyValuePair<string,int>("Red", 0));
ColorHandler.CurrentColors.Add(new KeyValuePair<string,int>("Blue", 1));
var f = ColorHandler.HandleEnumViaReflection(e);
如果e 是任何枚举的足够低的值,则设置f
到第 4 行的Color.Blue。此枚举未在第 3 行定义。
更新
实际上应该在构造函数中调用 HandleEnum()。
public ColorConsumer(dynamic color)
{
InstanceColor = HandleEnum(color);
}
// ...
//then we update HandleEnum very slightly
public object HandleEnum(object e)
{
int x = (int) e + 1;
return Enum.ToObject(typeof(C), x);
}
现在必须更新 HandleEnumViaReflection。
public static object HandleEnumViaReflection(object e)
{
var openType = typeof(ColorConsumer<>);
var typeToActivate = openType.MakeGenericType(new Type[]{ ColorType });
var consumer = Activator.CreateInstance(typeToActivate, new object[]{ e });
return consumer.InstanceColor;
}
其他一切都没有改变。