取消装箱通用参数中的可空枚举会导致问题
unboxing a nullable enum in a generic parameter is causing problems
我在通过通用变量传递可为 null 的枚举时遇到问题。
我目前正在使用反射为通用 类 创建 属性 setter。
这是代码
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
}
}
我只遇到可空枚举的问题,普通枚举没有。如果你 运行 这个例子你可以看到使用一个带有整数作为签名的委托,代码 运行 没问题。
问题 可空枚举迫使我在委托 setter 签名中使用枚举本身。当我实际上试图用一个值填充对象时,代码没有引用有问题的枚举,这是使用泛型的一点。我也不确定为什么我不能使用 int?对于可为空的枚举。欢迎任何见解!
此时我很想使用 PropertyInfo.SetValue 方法而不是委托。好像还行。
更新:下面的新 NullableEnumCopier class 不了解 someClass 或 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
}
}
我在通过通用变量传递可为 null 的枚举时遇到问题。
我目前正在使用反射为通用 类 创建 属性 setter。 这是代码
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
}
}
我只遇到可空枚举的问题,普通枚举没有。如果你 运行 这个例子你可以看到使用一个带有整数作为签名的委托,代码 运行 没问题。
问题 可空枚举迫使我在委托 setter 签名中使用枚举本身。当我实际上试图用一个值填充对象时,代码没有引用有问题的枚举,这是使用泛型的一点。我也不确定为什么我不能使用 int?对于可为空的枚举。欢迎任何见解!
此时我很想使用 PropertyInfo.SetValue 方法而不是委托。好像还行。
更新:下面的新 NullableEnumCopier class 不了解 someClass 或 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
}
}