2009-06-12 11 views
12

मुझे एक सामान्य उद्देश्य फ़ंक्शन चाहिए जो किसी भी ध्वज शैली enum के साथ उपयोग किया जा सकता है यह देखने के लिए कि कोई ध्वज मौजूद है या नहीं।सी #, फ्लैग एनम, जेनेरिक फ़ंक्शन ध्वज को देखने के लिए

यह संकलित नहीं करता है, लेकिन अगर किसी के पास कोई सुझाव है, तो मैं इसकी सराहना करता हूं।

public static Boolean IsEnumFlagPresent<T>(T value,T lookingForFlag) 
     where T:enum 
{ 
    Boolean result = ((value & lookingForFlag) == lookingForFlag); 
    return result ;    
} 
+3

बस एक ध्यान दें: सी # में 4 Enum struct एक मानक HasFlag() विधि प्रदान करता है। –

उत्तर

18

नहीं, आप इसे सी # जेनेरिक के साथ नहीं कर सकते हैं। हालांकि, अगर आप सकता है कार्य करें:

public static bool IsEnumFlagPresent<T>(T value, T lookingForFlag) 
    where T : struct 
{ 
    int intValue = (int) (object) value; 
    int intLookingForFlag = (int) (object) lookingForFlag; 
    return ((intValue & intLookingForFlag) == intLookingForFlag); 
} 

यह केवल enums जो int का एक अंतर्निहित प्रकार है के लिए काम करेंगे, और यह कुछ हद तक अक्षम है क्योंकि यह बॉक्स मूल्य ... लेकिन यह काम करना चाहिए है।

आप एक निष्पादन प्रकार जाँच लें कि टी वास्तव में एक enum प्रकार है जोड़ सकते हैं (उदाहरण के लिए typeof(T).BaseType == typeof(Enum))

यहां एक संपूर्ण यह प्रदर्शन कार्यक्रम काम कर रहा है:

using System; 

[Flags] 
enum Foo 
{ 
    A = 1, 
    B = 2, 
    C = 4, 
    D = 8 
} 

class Test 
{ 
    public static Boolean IsEnumFlagPresent<T>(T value, T lookingForFlag) 
     where T : struct 
    { 
     int intValue = (int) (object) value; 
     int intLookingForFlag = (int) (object) lookingForFlag; 
     return ((intValue & intLookingForFlag) == intLookingForFlag); 
    } 

    static void Main() 
    { 
     Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.A)); 
     Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.B)); 
     Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.C)); 
     Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.D)); 
    } 
} 
+1

यह आपको कुछ ऐसा करने देता है जो कि एनम नहीं है, हालांकि, और बहुत सुरक्षित नहीं है। यदि आप बॉक्स में जा रहे हैं, तो जेनरिक्स का उपयोग करने के बजाय पैरामीटर में सिस्टम.इनम के रूप में क्यों न दें? –

+1

यह सच है, कि यह भी करना होगा ... इसलिए आप अभी भी एक निष्पादन समय जांच आवश्यकता होगी यह आप दोनों मूल्यों के लिए "अशक्त" में पारित करने के लिए, बेशक अनुमति होगी ... –

+0

यह सामान्य बनाने का एक अन्य लाभ यह है कि यह जांचता है कि दोनों मान * समान * प्रकार हैं। आप ErrorCode.Foo, HttpStatusCode.Bar में पास नहीं कर सकते हैं। –

21

आप को बदलने के लिए देख रहे हैं कोड की एक पंक्ति को लपेटने वाले फ़ंक्शन के साथ कोड की रेखा? मैं सिर्फ कोड की एक पंक्ति का उपयोग करने के कहेंगे ...

+3

पवित्र गाय, मुझे स्कीट की तुलना में अधिक उछाल आया है। यह संभवतः आखिरी नहीं हो सकता ... :-) –

+6

यह एक अच्छा जवाब है - और मैंने इसके साथ जवाब देने के * सोच भी नहीं लिया। मैं सीधे चीजों के कार्यान्वयन पक्ष में चला गया। स्वयं को ध्यान दें: एक कदम वापस लेना चाहिए ... –

+1

यह इंगित करने लायक है कि करने की आवश्यकता है! = 0 == 0 इच्छा के आधार पर जांच कुछ लोगों के लिए दर्दनाक है जो सी/सी ++ शैली की शैली में उपयोग नहीं कर सकते हैं थोड़ा कष्टप्रद हो। बिंदु अभी भी +1 – ShuggyCoUk

1

आप जेनरिक के बिना यह कर सकते हैं:

static bool ContainsFlags(Enum value, Enum flag) 
{ 
    if (Enum.GetUnderlyingType(value.GetType()) == typeof(ulong)) 
     return (Convert.ToUInt64(value) & Convert.ToUInt64(flag)) == Convert.ToUInt64(flag); 
    else 
     return (Convert.ToInt64(value) & Convert.ToInt64(flag)) == Convert.ToInt64(flag); 
} 

मैं इस मामले में Int64 में कनवर्ट कर रहा हूँ, जो Ulong को छोड़कर हर मामले को संभाल चाहिए , यही कारण है कि अतिरिक्त जांच ...

+0

इस बक्से को इंगित करने के लायक है। हो सकता है कि कोई समस्या न हो, हालांकि – ShuggyCoUk

+0

हाँ, सच है। मैंने जॉन स्कीट की पोस्ट पर अपनी टिप्पणी में इसका उल्लेख किया, लेकिन इसे मेरे जवाब में रखने के लिए उपेक्षित किया। –

0

ठीक है, मुझे विश्वास नहीं है कि ऐसा करने का कोई तरीका है, क्योंकि बिटवाई ऑपरेटरों पर लागू होने वाली कोई बाधा नहीं है।

हालांकि ... आप केवल अपनी enum int int और इसे कर सकते हैं।

public static Boolean IsEnumFlagPresent(int value,int lookingForFlag) 
{ 
    return ((value & lookingForFlag) == lookingForFlag); 
} 

यह काम करता है, लेकिन किसी के लिए भ्रमित हो सकता है।

+0

ध्यान दें कि यह उन enums के लिए काम नहीं करेगा जो ints नहीं हैं ... सामान्य मामले के लिए प्रभावी हालांकि – ShuggyCoUk

+0

सच है, आपको अन्य मूल्य प्रकारों के लिए ओवरलोड प्रदान करना होगा। यह भी ध्यान रखें कि आप केवल ValueType का उपयोग नहीं कर सकते क्योंकि यह bitwise ऑपरेटरों के साथ काम नहीं करता है। – Will

1

वर्थ यह इंगित करता है कि सभी अभिन्न प्रकारों के लिए बस कुछ स्थिर अधिभार प्रदान करते हैं, जब तक आप जानते हैं कि आप एक विशिष्ट enum के साथ काम कर रहे हैं। अगर उपभोक्ता कोड वैसे ही where t : struct

पर काम कर रहा है वे आपको मनमाना (struct) टी

आप वर्तमान में कुछ वैकल्पिक बिटवाइज़ रूप में एक सामान्य रूप से टाइप किए हुए struct की एक तेजी से रूपांतरण नहीं कर सकता से निपटने के लिए की जरूरत है काम नहीं करेगा सी का उपयोग किए बिना (यानी मोटे तौर पर एक reinterpret_cast बोल) ++/CLI

generic <typename T> 
where T : value class 
public ref struct Reinterpret 
{ 
    private: 
    const static int size = sizeof(T); 

    public:  
    static int AsInt(T t) 
    { 
     return *((Int32*) (void*) (&t)); 
    } 
} 

यह तो दूँगी आप लिखते हैं:

static void IsSet<T>(T value, T flags) where T : struct 
{ 
    if (!typeof(T).IsEnum) 
     throw new InvalidOperationException(typeof(T).Name +" is not an enum!"); 
    Type t = Enum.GetUnderlyingType(typeof(T)); 
    if (t == typeof(int)) 
    { 
     return (Reinterpret.AsInt(value) & Reinterpret.AsInt(flags)) != 0 
    } 
    else if (t == typeof(byte)) 
    { 
     return (Reinterpret.AsByte(value) & Reinterpret.AsByte(flags)) != 0 
    } 
    // you get the idea...   
} 

आप enums को बाध्य नहीं कर सकते हैं। लेकिन इन विधियों की गणितीय वैधता नहीं बदली जाती है अगर उन्हें गैर enum प्रकारों के साथ उपयोग किया जाता है ताकि आप उन्हें अनुमति दे सकें यदि आप यह निर्धारित कर सकते हैं कि वे प्रासंगिक आकार की संरचना में परिवर्तनीय हैं।

2

इसके लिए एक विस्तार विधि क्यों नहीं लिखें?I did this in another post

public static class EnumerationExtensions { 

    public static bool Has<T>(this System.Enum type, T value) { 
     try { 
      return (((int)(object)type & (int)(object)value) == (int)(object)value); 
     } 
     catch { 
      return false; 
     } 
    } 
    //... etc... 

} 

//Then use it like this 
bool hasValue = permissions.Has(PermissionTypes.Delete); 

यह थोड़ा शोधन (क्योंकि यह मान लिया गया है सब कुछ एक पूर्णांक के रूप में ढाला जा सकता है) इस्तेमाल कर सकते हैं, लेकिन यह हो सकता है कि आप आरंभ ...

6

मैंने पहले इस का इस्तेमाल किया है:

public static bool In<T>(this T me, T values) 
    where T : struct, IConvertible 
{ 
    return (me.ToInt64(null) & values.ToInt64(null)) > 0; 
} 

मुझे इसके बारे में क्या पसंद है आप इसे 3.5 में से कॉल करने के लिए इस स्वच्छ वाक्यविन्यास का उपयोग कर सकते हैं क्योंकि संकलक जेनेरिक पैरामीटर का अनुमान लगा सकता है।

AttributeTargets a = AttributeTargets.Class; 
if (a.In(AttributeTargets.Class | AttributeTargets.Module)) 
{ 
    // ... 
} 
+0

यह बहुत अच्छा है – Hugoware

9

इसके लायक होने के लिए, मैंने हाल ही में पढ़ा है कि यह सुविधा .NET 4.0 का हिस्सा होगी। विशेष रूप से, यह Enum.HasFlag() फ़ंक्शन में लागू किया गया है।

+0

वास्तव में, यह सिर्फ मुझे पता चला है। – Trax72

0

प्रश्न से अधिक लंबी है, लेकिन यहां संदर्भ के लिए एक वैसे भी:

public static bool HasFlag<TEnum>(this TEnum enumeratedType, TEnum value) 
     where TEnum : struct, IComparable, IFormattable, IConvertible 

    { 
     if (!(enumeratedType is Enum)) 
     { 
      throw new InvalidOperationException("Struct is not an Enum."); 
     } 

     if (typeof(TEnum).GetCustomAttributes(
      typeof(FlagsAttribute), false).Length == 0) 
     { 
      throw new InvalidOperationException("Enum must use [Flags]."); 
     } 

     long enumValue = enumeratedType.ToInt64(CultureInfo.InvariantCulture); 
     long flagValue = value.ToInt64(CultureInfo.InvariantCulture); 

     if ((enumValue & flagValue) == flagValue) 
     { 
      return true; 
     } 

     return false; 
    } 
संबंधित मुद्दे