c# समय सी#में झंडे की तुलना कैसे करें?




सबसे पहले तिरंगा किसने फहराया (9)

मेरे पास नीचे एक झंडा enum है।

[Flags]
public enum FlagTest
{
    None = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4
}

अगर मैं कथन का सही मूल्यांकन नहीं कर सकता हूं।

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

if (testItem == FlagTest.Flag1)
{
    // Do something,
    // however This is never true.
}

मैं यह कैसे सच कर सकता हूं?


.NET 4 में एक नई विधि Enum.HasFlag । यह आपको लिखने की अनुमति देता है:

if ( testItem.HasFlag( FlagTest.Flag1 ) )
{
    // Do Stuff
}

जो बहुत अधिक पठनीय, आईएमओ है।

.NET स्रोत इंगित करता है कि यह स्वीकार्य उत्तर के समान तर्क करता है:

public Boolean HasFlag(Enum flag) {
    if (!this.GetType().IsEquivalentTo(flag.GetType())) {
        throw new ArgumentException(
            Environment.GetResourceString(
                "Argument_EnumTypeDoesNotMatch", 
                flag.GetType(), 
                this.GetType()));
    }

    ulong uFlag = ToUInt64(flag.GetValue()); 
    ulong uThis = ToUInt64(GetValue());
    // test predicate
    return ((uThis & uFlag) == uFlag); 
}

इसे इस्तेमाल करे:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
असल में, आपका कोड पूछ रहा है कि क्या दोनों झंडे सेट एक फ्लैग सेट होने जैसा ही है, जो स्पष्ट रूप से झूठा है। उपरोक्त कोड केवल ध्वज 1 बिट सेट को छोड़ देगा यदि यह बिल्कुल सेट है, तो इस परिणाम को फ्लैग 1 पर तुलना करता है।


सलाह का एक और टुकड़ा ... ध्वज के साथ मानक द्विआधारी जांच कभी नहीं करें जिसका मूल्य "0" है। इस ध्वज पर आपकी जांच हमेशा सच होगी।

[Flags]
public enum LevelOfDetail
{
    [EnumMember(Value = "FullInfo")]
    FullInfo=0,
    [EnumMember(Value = "BusinessData")]
    BusinessData=1
}

यदि आप FullInfo के खिलाफ इनपुट पैरामीटर बाइनरी जांचते हैं - आपको मिलता है:

detailLevel = LevelOfDetail.BusinessData;
bool bPRez = (detailLevel & LevelOfDetail.FullInfo) == LevelOfDetail.FullInfo;

बीपीआरज़ हमेशा कुछ और 0 हमेशा == 0 के रूप में सच रहेगा।

इसके बजाय आपको बस यह जांचना चाहिए कि इनपुट का मान 0 है:

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);

बिट ऑपरेशंस के लिए, आपको बिटवाई ऑपरेटरों का उपयोग करने की आवश्यकता है।

यह काम कर जाना चाहिए:

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // Do something,
    // however This is never true.
}

संपादित करें: अगर मेरा चेक फिक्स्ड - मैं अपने सी / सी ++ तरीकों से वापस फिसल गया (रयान फर्ले को धन्यवाद देने के लिए धन्यवाद)


उन लोगों के लिए जिन्हें स्वीकार्य समाधान (जो यह है) के साथ क्या हो रहा है, कल्पना करने में परेशानी है,

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // Do stuff.
}

testItem (प्रश्न के अनुसार) के रूप में परिभाषित किया गया है,

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

फिर, अगर कथन में, तुलना के बाएं हाथ की तरफ है,

(testItem & flag1) 
 = (011 & 001) 
 = 001

और पूर्ण अगर कथन (जो testItem में testItem 1 सेट किया गया है तो सत्य का मूल्यांकन करता है)

(testItem & flag1) == flag1
 = (001) == 001
 = true

if((testItem & FlagTest.Flag1) == FlagTest.Flag1) 
{
...
}

मैंने इसे करने के लिए एक विस्तार विधि स्थापित की: संबंधित प्रश्न

मूल रूप से:

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}

फिर आप कर सकते हैं:

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;

if( testItem.IsSet ( FlagTests.Flag1 ) )
    //Flag1 is set

संयोग से मैं सम्मेलन का उपयोग करता हूं जो मानक के लिए एकवचन है, झंडे के लिए बहुवचन। इस तरह आप enum नाम से जानते हैं कि क्या यह कई मान रख सकता है।


यहां तक ​​कि [झंडे] के बिना, आप इस तरह कुछ उपयोग कर सकते हैं

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=0){
//..
}

या यदि आपके पास शून्य मूल्य enum है

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}

@ फिल-Devaney

ध्यान दें कि मामलों के सबसे सरलतम को छोड़कर, Enum.HasFlag मैन्युअल रूप से कोड लिखने की तुलना में भारी प्रदर्शन जुर्माना रखता है। निम्नलिखित कोड पर विचार करें:

[Flags]
public enum TestFlags
{
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}


class Program
{
    static void Main(string[] args)
    {
        TestFlags f = TestFlags.Five; /* or any other enum */
        bool result = false;

        Stopwatch s = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            result |= f.HasFlag(TestFlags.Three);
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*

        s.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            result |= (f & TestFlags.Three) != 0;
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*        

        Console.ReadLine();
    }
}

10 मिलियन से अधिक पुनरावृत्तियों, मानक बिटवाई कार्यान्वयन के लिए 27 एमएस की तुलना में हैस्फ्लैग एक्सटेंशन विधि में 47 9 3 एमएस की भारी मात्रा है।





flags