![](/img/trans.png)
[英]Is there a good way to use logical operations on System.Enum in C#?
[英]General handling of System.Enum values regardless of underlying type in C#
我實現了一個方法,它將兩個枚舉值作為參數:
void HandleEnumValue( System.Enum v, System.Enum bits )
兩個參數的實際枚舉類型不一定相同。
在這個方法中,我假設枚舉的基礎類型是int。 現在,第一次使用枚舉值調用此方法,該值作為基礎類型,並且該方法現在拋出異常。
我喜歡增強方法,以便它可以采用任何枚舉值 ,無論底層類型如何。 我有一個實現,但我不太喜歡它。
我想知道是否有更通用/可維護的解決方案?
唉,我不能使用泛型類型參數,因為這會在庫中引入重大變化,並且必須替換對我的方法的數以萬計的調用。
這是代碼,我不太好的解決方案:
using System;
[Flags()] public enum ByteEnum : byte { One = 1, SomeByte = 0x42 }
[Flags()] public enum ShortEnum: short{ One = 1, SomeShort = 0x4223 }
[Flags()] public enum IntEnum : int { One = 1, SomeInt = 0x42230815 }
[Flags()] public enum LongEnum : long { One = 1, SomeLong = 0x4223081547112012L }
public class Program
{
public static void Main()
{
HandleEnumValue( ByteEnum.SomeByte, ByteEnum.One ) ;
HandleEnumValue( ShortEnum.SomeShort, ShortEnum.One ) ;
HandleEnumValue( IntEnum.SomeInt, IntEnum.One ) ;
HandleEnumValue( LongEnum.SomeLong, LongEnum.One ) ;
// will throw InvalidCastException: HandleEnumValueOriginal( ByteEnum.SomeByte, ByteEnum.One ) ;
// will throw InvalidCastException: HandleEnumValueOriginal( ShortEnum.SomeShort, ShortEnum.One ) ;
HandleEnumValueOriginal( IntEnum.SomeInt, IntEnum.One ) ;
// will throw InvalidCastException: HandleEnumValueOriginal( LongEnum.SomeLong, LongEnum.One ) ;
}
// new implementation, that I dislike.
static void HandleEnumValue( System.Enum v, System.Enum bits )
{
// assert underlying types of v and bits are equal
if ( v.GetTypeCode() != bits.GetTypeCode() ) throw new Exception( "enum type code mismatch" ) ;
bool hasBitsSet = false ; // won't compile: bool hasBitsSet = ( ( v & bits ) == bits ) ;
long lvalue = 0L ; // will throw : lvalue = (long)(object)v
switch ( v.GetTypeCode() )
{
case TypeCode.Byte :
hasBitsSet = ( ( (byte)(object)v & (byte)(object)bits ) == (byte)(object)bits ) ;
lvalue = (long)(byte)(object)v ;
break ;
case TypeCode.Int16 :
hasBitsSet = ( ( (short)(object)v & (short)(object)bits ) == (short)(object)bits ) ;
lvalue = (long)(short)(object)v ;
break ;
case TypeCode.Int32 :
hasBitsSet = ( ( (int)(object)v & (int)(object)bits ) == (int)(object)bits ) ;
lvalue = (long)(int)(object)v ;
break ;
case TypeCode.Int64 :
hasBitsSet = ( ( (long)(object)v & (long)(object)bits ) == (long)(object)bits ) ;
lvalue = (long)(object)v ;
break ;
}
Console.WriteLine( "(new) enum value = " + v.ToString() ) ;
Console.WriteLine( "(new) number value = " + lvalue.ToString() ) ;
Console.WriteLine( "(new) has bits set = " + hasBitsSet.ToString() ) ;
// further processing ...
}
// original implementation, that doesn't work anymore
static void HandleEnumValueOriginal( System.Enum v, System.Enum bits )
{
int lvalue = (int)(object)v ;
bool hasBitsSet = ( ( (int)(object)v & (int)(object)bits ) == (int)(object)bits ) ;
Console.WriteLine( "(original) enum value = " + v.ToString() ) ;
Console.WriteLine( "(original) number value = " + lvalue.ToString() ) ;
Console.WriteLine( "(original) has bits set = " + hasBitsSet.ToString() ) ;
// further processing ...
}
}
在.NET 4中,有一個添加的方法幾乎可以滿足您的需求: Enum.HasFlag 。
不幸的是,如果實際的枚舉類型不同,則拋出此方法。 它的實現非常簡單,無需枚舉類型檢查即可復制,或者如果您使用的是舊版本的框架:
static void HandleEnumValue(Enum v, Enum bits) {
ulong enumValue = ToUInt64(v);
ulong bitsValue = ToUInt64(bits);
bool hasBitsSet = (enumValue & bitsValue) == bitsValue;
Console.WriteLine("enum value = " + v);
Console.WriteLine("number value = " + bits);
Console.WriteLine("has bits set = " + hasBitsSet);
}
internal static ulong ToUInt64(Enum value) {
switch (Convert.GetTypeCode(value)) {
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return (ulong) Convert.ToInt64(value);
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return Convert.ToUInt64(value);
default:
throw new ArgumentOutOfRangeException("value");
}
}
此方法將處理任何類型的枚舉和任何基礎類型,即使它們不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.