我可以|
和&
等,enum
,但不能Enum
。为什么是这样?有没有办法解决?我试图为WPF写一个Enum标志转换器。
public class EnumFlagConverter : IValueConverter
{
public Enum CurrentValue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var theEnum = value as Enum;
CurrentValue = theEnum;
return theEnum.HasFlag(parameter as Enum);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum CurrentValue;
var theEnum = parameter as Enum;
if (CurrentValue.HasFlag(theEnum)) //this line is allowed
return CurrentValue &= ~theEnum; //~theEnum not allowed, neither is the &=
else
return CurrentValue |= theEnum; // |= cannot be applied to Enum and Enum
}
}
答案 0 :(得分:9)
为什么会这样?
如果编译器知道枚举的基础类型,编译器可以执行按位运算而不会出现任何问题。在编译器不知道底层类型的情况下,它无法知道您是想要一个8位,一个16位,一个32位,甚至是64位操作,而只是完全放弃。另请注意,编译器无法知道您的两个枚举值都不是null
,并且编译器无法知道两个枚举值具有相同的类型甚至宽度。
有什么方法吗?
您可以知道,您永远不会处理大于64位的枚举,并且即使对于8位枚举类型,64位运算也会产生正确的结果。因此,您可以通过明确地将操作编写为64位操作来帮助编译器。
static Enum Or(Enum a, Enum b)
{
// consider adding argument validation here
if (Enum.GetUnderlyingType(a.GetType()) != typeof(ulong))
return (Enum)Enum.ToObject(a.GetType(), Convert.ToInt64(a) | Convert.ToInt64(b));
else
return (Enum)Enum.ToObject(a.GetType(), Convert.ToUInt64(a) | Convert.ToUInt64(b));
}
同样适用于And
。
答案 1 :(得分:1)
使用接受的答案,我精心设计了这个转换器,将多个复选框绑定到[Flags]Enum
。 注意:此转换器使用类成员,因此不要为多组绑定重用相同的转换器实例。
XAML:
<StackPanel>
<StackPanel.Resources>
<local:EnumFlagConverter x:Key="myConverter" />
</StackPanel.Resources>
<CheckBox Content="Option1" IsChecked="{Binding TheEnum, Converter={StaticResource myConverter}, ConverterParameter={x:Static local:MyEnum.Option1}}" />
<CheckBox Content="Option2" IsChecked="{Binding TheEnum, Converter={StaticResource myConverter}, ConverterParameter={x:Static local:MyEnum.Option2}}" />
<CheckBox Content="Option3" IsChecked="{Binding TheEnum, Converter={StaticResource myConverter}, ConverterParameter={x:Static local:MyEnum.Option3}}" />
</StackPanel>
C#:
public class EnumFlagConverter : IValueConverter
{
public Enum CurrentValue { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var theEnum = value as Enum;
CurrentValue = theEnum;
return theEnum.HasFlag(parameter as Enum);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var theEnum = parameter as Enum;
if (CurrentValue.HasFlag(theEnum))
CurrentValue = CurrentValue.And(theEnum.Not());
else
CurrentValue = CurrentValue.Or(theEnum);
return CurrentValue;
}
}
public static class Extensions
{
public static Enum Or(this Enum a, Enum b)
{
// consider adding argument validation here
if (Enum.GetUnderlyingType(a.GetType()) != typeof(ulong))
return (Enum)Enum.ToObject(a.GetType(), Convert.ToInt64(a) | Convert.ToInt64(b));
else
return (Enum)Enum.ToObject(a.GetType(), Convert.ToUInt64(a) | Convert.ToUInt64(b));
}
public static Enum And(this Enum a, Enum b)
{
// consider adding argument validation here
if (Enum.GetUnderlyingType(a.GetType()) != typeof(ulong))
return (Enum)Enum.ToObject(a.GetType(), Convert.ToInt64(a) & Convert.ToInt64(b));
else
return (Enum)Enum.ToObject(a.GetType(), Convert.ToUInt64(a) & Convert.ToUInt64(b));
}
public static Enum Not(this Enum a)
{
// consider adding argument validation here
return (Enum)Enum.ToObject(a.GetType(), ~Convert.ToInt64(a));
}
}