2014-06-11 17 views
5

Mogę | i & itd., enum, ale nie Enum. Dlaczego to? Czy jest jakiś sposób obejścia tego? Próbuję napisać konwerter flagi Enum dla WPF.Operator "|" nie można zastosować do operandów typu "System.Enum" i "System.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

można określić typ jako 'int' zamiast, i mam nadzieję, że niejawna konwersja do' Enum' działa? – Matthew

+2

Zgodziłbyś się "Ponieważ Enum jest klasą, która nie ma zdefiniowanych operacji" Myślę, że nie rozumiem zamieszania. Z tego samego powodu nie możesz zrobić ciągu foo | = "bar" –

+0

Pomocne może być także zrozumienie, że "Enum" (System.Enum faktycznie) jest typem, podczas gdy "enum" jest słowem kluczowym używanym do deklarowania rodzaj. –

Odpowiedz

7

Dlaczego tak jest?

W przypadkach, w których kompilator zna właściwy typ wyliczenia, kompilator może wykonywać operacje bitowe bez żadnych problemów. W przypadkach, gdy kompilator nie zna typu bazowego, nie może wiedzieć, czy ma być operacja 8-bitowa, 16-bitowa, 32-bitowa, a może nawet 64-bitowa, i po prostu całkowicie rezygnuje. Zauważ też, że kompilator nie może wiedzieć, że żadna z twoich wartości wyliczeniowych nie jest null, i że kompilator nie może wiedzieć, że te dwie wartości wyliczeniowe mają ten sam typ lub nawet szerokość.

Czy jest jakiś sposób obejścia tego?

Można wiedzieć, że nigdy nie będziesz mieć do czynienia z wyliczeń większych niż 64 bitów i że operacja 64-bitowy będzie produkować poprawne wyniki nawet dla 8-bitowych typów wyliczeniowych tutaj. Dlatego możesz pomóc kompilatorowi, pisząc operacje bezpośrednio w 64-bitowych operacjach.

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

podobnie dla And.

+0

Idealny! Wiedziałem, że jest jakiś sposób, aby zamienić Enum w jego obiekt, ale nie wiedziałem o metodzie "ToObject". Dzięki! – DLeh

0

Za pomocą zaakceptowanej odpowiedzi utworzyłem ten konwerter, aby powiązać wiele pól wyboru z [Flags]Enum. Uwaga: ten konwerter używa elementu klasy, więc nie używaj ponownie tej samej instancji konwertera dla wielu zestawów powiązań.

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)); 
    } 
} 
Powiązane problemy