static object HandleEnumViaReflection(object e)
{
int x = (int) e + 1;
return Activator.CreateInstance(e.GetType(), x);
}
This does not work--but it could. In fact we can create the type if it can't be found at runtime.
If you must use reflection or other indirect means then you could define your own enumeration with a ModuleBuilder instance and an IEnumerable<KeyValuePair<string,int>>
. Below we are passing in the IEnumerable only because it simplifies the method body.
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);
}
This is not generally a good way to achieve your purpose but it can be useful when the color palette is not known in advance (i.e., at design or build time).
However most would extract the type generation into a separate static method in this case so that among other things we could avoid rebuilding the missing type.
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);
}
}
Now we are almost full circle. Especially if we have a generic class and still want to use Activator.CreateInstance() in a non-trivial way.
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);
}
}
Now we can update the ColorHandler class.
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();
}
}
Now we have both generic parameters and a call to Activator.CreateInstance().
QEF.
Let's see what it looks like to call this.
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);
If e
is a sufficiently low value of any enumeration then f
is set
to Color.Blue
on line 4. This enumeration is not defined on line 3.
Update
Actually HandleEnum() should be invoked in the constructor.
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);
}
Now HandleEnumViaReflection must be updated.
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;
}
All else is unchanged.