运营商' |'不能应用于类型' System.Enum'的操作数。和' System.Enum'

时间:2014-06-11 20:53:13

标签: c# wpf

我可以|&等,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
    }
}

2 个答案:

答案 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));
    }
}