Reputation: 1469
I am having trouble passing a nullable enum through a generic variable.
I currently am using reflection to create property setters for generic classes. here is the code
public static class program
{
static void Main(string[] args)
{
someClass testclass = new someClass();
PropertyInfo enumProperty = typeof(someClass).GetProperties()[0];
Action<someClass, int> enumDelegate = CreateSetterFromPropertyInfo<someClass, int>(enumProperty);
enumDelegate(testclass, 2);
Console.WriteLine(testclass.enumVal.ToString()); // writes B
object nullableSetter = null;
PropertyInfo enumPropertyNullable = typeof(someClass).GetProperties()[1];
if (enumPropertyNullable.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (enumPropertyNullable.PropertyType.GetGenericArguments().First().IsEnum)
{
// the step below determines the method signature. I cannot deviate from what the property tells me.
// if I use int? instead of the PropertyType I get an ArgumentException.
MethodInfo method = typeof(program).GetMethod("CreateSetterFromPropertyInfo", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(new Type[] { typeof(someClass), enumPropertyNullable.PropertyType });
nullableSetter = method.Invoke(null, new object[] { enumPropertyNullable });
}
}
if (nullableSetter != null)
{
Action<someClass, someEnum?> cast1 = (Action<someClass, someEnum?>) nullableSetter;
Action<someClass, Nullable<someEnum>> cast2 = (Action<someClass, Nullable<someEnum>>)nullableSetter;
// Action<someClass, Nullable<int>> cast3 = (Action<someClass, Nullable<int>>)nullableSetter;
// Action<someClass, Enum> cast4 = (Action<someClass, Enum>)nullableSetter;
// at this point I am trying to cast a string to a enum. That works. However the parameter should be a nullable enum.
Type subtype = enumPropertyNullable.PropertyType.GetGenericArguments().First();
Enum result = Enum.Parse(subtype, "B") as Enum;
// here is where I am getting the error. I can't find a way to cast the string I have to a nullable enum.
//cast1(testclass, result);
}
}
private static Action<C, P> CreateSetterFromPropertyInfo<C, P>(PropertyInfo property)
{
Action<C, P> setForAnyProperty = (Action<C, P>)Delegate.CreateDelegate(typeof(Action<C, P>), null, property.GetSetMethod());
return setForAnyProperty;
}
public class someClass
{
public someEnum enumVal {get; set;}
public someEnum? enumValNullable { get; set; }
}
public enum someEnum
{
A = 1,
B = 2
}
}
I only get issues with the nullable enums, not the normal enums. if you run the example you can see that using an delegate with an integer as signature, the code runs fine.
The problem when the nullable enums force me to use the enum itself in the delegate setter signature. When i am actually trying to fill the object with a value, the code has no reference to the enum in question, which is kind of the point for using generics. I am also unsure why I cannot use a int? for the nullable enum. Any insights are welcome!
At this point I am tempted to use the PropertyInfo.SetValue method instead of a delegate. It seems to work.
Upvotes: 1
Views: 330
Reputation: 2608
UPDATED: The new NullableEnumCopier class below has no knowledge of someClass or someEnum.
public static class program
{
static void Main(string[] args)
{
someClass testclass = new someClass();
NullableEnumCopier<someClass, someEnum>.Copy(testclass);
}
public static class NullableEnumCopier<TClass, TEnum> where TEnum : struct
{
public static void Copy(TClass item)
{
PropertyInfo enumProperty = typeof(TClass).GetProperties()[0];
Action<TClass, int> enumDelegate = CreateSetterFromPropertyInfo<TClass, int>(enumProperty);
enumDelegate(item, 2);
//Console.WriteLine(item.enumVal.ToString()); // writes B
object nullableSetter = null;
PropertyInfo enumPropertyNullable = typeof(TClass).GetProperties()[1];
if (enumPropertyNullable.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (enumPropertyNullable.PropertyType.GetGenericArguments().First().IsEnum)
{
// the step below determines the method signature. I cannot deviate from what the property tells me.
// if I use int? instead of the PropertyType I get an ArgumentException.
MethodInfo method = typeof(program).GetMethod("CreateSetterFromPropertyInfo", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(new Type[] { typeof(TClass), enumPropertyNullable.PropertyType });
nullableSetter = method.Invoke(null, new object[] { enumPropertyNullable });
}
}
if (nullableSetter != null)
{
Action<TClass, TEnum?> cast1 = (Action<TClass, TEnum?>) nullableSetter;
Action<TClass, Nullable<TEnum>> cast2 = (Action<TClass, Nullable<TEnum>>)nullableSetter;
// Action<TClass, Nullable<int>> cast3 = (Action<TClass, Nullable<int>>)nullableSetter;
// Action<TClass, Enum> cast4 = (Action<TClass, Enum>)nullableSetter;
// at this point I am trying to cast a string to a enum. That works. However the parameter should be a nullable enum.
Type subtype = enumPropertyNullable.PropertyType.GetGenericArguments().First();
Enum result = Enum.Parse(subtype, "B") as Enum;
// here is where I am getting the error. I can't find a way to cast the string I have to a nullable enum.
cast1(item, (TEnum?)(object)result);
}
}
}
private static Action<C, P> CreateSetterFromPropertyInfo<C, P>(PropertyInfo property)
{
Action<C, P> setForAnyProperty = (Action<C, P>)Delegate.CreateDelegate(typeof(Action<C, P>), null, property.GetSetMethod());
return setForAnyProperty;
}
public class someClass
{
public someEnum enumVal {get; set;}
public someEnum? enumValNullable { get; set; }
}
public enum someEnum
{
A = 1,
B = 2
}
}
Upvotes: 1