سؤال

لدي العلم التعداد أدناه.

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

أنا لا يمكن أن تجعل إذا كان البيان تقييمها إلى true.

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

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

كيف يمكنني جعل هذا صحيح ؟

هل كانت مفيدة؟

المحلول

في .صافي 4 هناك طريقة جديدة Enum.HasFlag.هذا يسمح لك أن تكتب:

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

الذي هو أكثر قابلية للقراءة ، المنظمة البحرية الدولية.

على .صافي المصدر يشير إلى أن هذا يؤدي نفس المنطق المقبول الجواب:

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
}

(testItem & FlagTest.Flag1) هو أحادي المعامل وتشغيلها.

FlagTest.Flag1 ما يعادل 001 مع OP enum.الآن دعونا نقول testItem وقد Flag1 و Flag2 (حتى انها أحادي المعامل 101):

  001
 &101
 ----
  001 == FlagTest.Flag1

بالنسبة لأولئك الذين لديهم صعوبة في تصور ما يحدث مع الحل المقبول (وهو هذا) ،

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

testItem (كما في السؤال) بأنه:

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

ثم في إن بيان الجانب الأيسر من المقارنة ،

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

الكامل إذا كان البيان (التي يتم تقييمها إلى true إذا flag1 في testItem),

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

@فيل-ديفاني

علما أن ما عدا في أبسط الحالات ، 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 مليون التكرار ، HasFlags طريقة التمديد يأخذ ضخم 4793 ms, مقارنة مع 27 ms القياسية المختصة بالبت التنفيذ.

يجب تمديد طريقة للقيام بذلك: ذات السؤال.

في الأساس:

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

بالمناسبة الاتفاقية تستخدم enums هو المفرد القياسية ، الجمع أعلام.بهذه الطريقة أنت تعرف من التعداد اسم ما إذا كان يمكن أن تعقد متعددة القيم.

أكثر من قطعة واحدة من المشورة...لم تفعل الثنائية القياسية تحقق مع العلم قيمتها "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;

bPRez سوف يكون دائما صحيحا أي شيء & 0 = دائما= 0.


بدلا من ذلك يمكنك ببساطة تحقق من أن قيمة الإدخال 0:

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);
if((testItem & FlagTest.Flag1) == FlagTest.Flag1) 
{
...
}

عمليات قليلا, تحتاج إلى استخدام جميع المشغلين.

هذا ينبغي أن تفعل خدعة:

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

تحرير: إصلاح بلدي إذا تحقق - تراجع عدت الى بلدي C/C++ طرق (بفضل ريان فارلي لافتا بها)

بشأن تعديل.لا يمكنك إجراء صحيح.أقترح عليك التفاف ما تريد إلى فئة أخرى (أو طريقة التمديد) للحصول على أقرب إلى الجملة التي تحتاج إليها.

أي

public class FlagTestCompare
{
    public static bool Compare(this FlagTest myFlag, FlagTest condition)
    {
         return ((myFlag & condition) == condition);
    }
}

جرب هذا:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
أساسا التعليمات البرمجية يسأل إذا كان وجود كل أعلام مجموعة هو نفس وجود راية واحدة مجموعة, التي من الواضح انها كاذبة.رمز أعلاه سوف يغادر فقط Flag1 مجموعة بت إذا كان يقع في كل شيء ، ثم يقارن هذه النتيجة إلى Flag1.

حتى من دون [الأعلام] ، يمكن استخدام شيء مثل هذا

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

أو إذا كان لديك قيمة صفر enum

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top