2014-06-11 23 views
5

Tôi có thể |&, v.v., enum, nhưng không phải là Enum. Tại sao điều này? Có cách nào để khắc phục điều này? Tôi đang cố gắng viết một công cụ chuyển đổi cờ Enum cho WPF.Toán tử '|' không thể áp dụng cho các toán hạng của loại 'System.Enum' và '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

bạn có thể xác định loại là 'int' thay vào đó, và hy vọng rằng chuyển đổi ngầm cho' Enum' hoạt động? – Matthew

+2

Bạn có chấp nhận "Vì Enum là một lớp không có các hoạt động đó được định nghĩa" Tôi đoán tôi đang gặp khó khăn khi hiểu nhầm lẫn. Đó cũng là lý do bạn không thể thực hiện chuỗi foo | = "bar" –

+0

Cũng có thể hữu ích khi hiểu rằng "Enum" (System.Enum thực sự) là một loại, trong khi "enum" là từ khóa được sử dụng để khai báo kiểu. –

Trả lời

7

Tại sao điều này?

Trong trường hợp trình biên dịch biết loại cơ bản của liệt kê, trình biên dịch có thể thực hiện thao tác bitwise mà không gặp bất kỳ sự cố nào. Trong trường hợp trình biên dịch không biết loại cơ bản, nó không thể biết liệu bạn có muốn một thao tác 8 bit, 16 bit, 32 bit, hoặc thậm chí là 64 bit, và chỉ hoàn toàn từ bỏ. Cũng lưu ý rằng trình biên dịch không có cách nào để biết rằng cả hai giá trị liệt kê của bạn là null và trình biên dịch không có cách nào biết rằng hai giá trị liệt kê có cùng loại hoặc thậm chí chiều rộng.

Có cách nào xung quanh vấn đề này không?

Bạn có thể biết rằng bạn sẽ không bao giờ xử lý các liệt kê lớn hơn 64 bit và thao tác 64 bit sẽ tạo kết quả chính xác ngay cả đối với các loại liệt kê 8 bit tại đây. Vì vậy, bạn có thể giúp trình biên dịch bằng cách viết các hoạt động của bạn dưới dạng hoạt động 64 bit một cách rõ ràng.

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

tương tự cho And.

+0

Hoàn hảo! Tôi biết có một số cách để biến Enum thành đối tượng cơ bản của nó, nhưng tôi không biết về phương thức 'ToObject'. Cảm ơn! – DLeh

0

Sử dụng câu trả lời được chấp nhận, tôi đã tạo công cụ chuyển đổi này để liên kết nhiều hộp kiểm với số [Flags]Enum. Lưu ý: công cụ chuyển đổi này sử dụng một thành viên nhóm, do đó, không sử dụng lại cùng một cá thể chuyển đổi cho nhiều bộ ràng buộc.

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)); 
    } 
} 
Các vấn đề liên quan