【问题标题】:Operator '|' cannot be applied to operands of type 'System.Enum' and 'System.Enum'运算符“|”不能应用于“System.Enum”和“System.Enum”类型的操作数
【发布时间】:2020-04-10 00:51:03
【问题描述】:

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

【问题讨论】:

  • 您能否将类型指定为int,并希望隐式转换为Enum 有效?
  • 你会接受“因为 Enum 是一个没有定义这些操作的类”我想我很难理解这种混淆。这和你不能做 string foo |= "bar" 的原因是一样的
  • 了解“Enum”(实际上是 System.Enum)是一种类型,而“enum”是用于声明类型的关键字,这也可能会有所帮助。
  • 当转换器用于多个绑定时,您将如何跟踪绑定源的“当前值”? IMO 反向转换根本没有意义。您至少应该从 ConvertBack 方法中删除本地 CurrentValue 变量。
  • @Clemens 我不必为多个绑定使用同一个转换器,如果这是我必须处理的限制的话。

标签: c# wpf


【解决方案1】:

这是为什么?

在编译器知道枚举的基础类型的情况下,编译器可以执行按位运算而不会出现任何问题。在编译器不知道底层类型的情况下,它无法知道您是否需要 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 也是如此。

【讨论】:

  • 完美!我知道有一些方法可以将 Enum 变成它的底层对象,但我不知道 ToObject 方法。谢谢!
【解决方案2】:

使用公认的答案,我制作了这个转换器来将多个复选框绑定到[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 ((bool)value)
            CurrentValue = CurrentValue.Or(theEnum);
        else
            CurrentValue = CurrentValue.And(theEnum.Not());
        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));
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-27
    • 2020-10-19
    • 2014-05-27
    • 2015-01-25
    • 2011-12-31
    • 2011-04-03
    • 2018-04-04
    • 2014-10-13
    相关资源
    最近更新 更多