จะวนซ้ำค่าของ Enum ที่มีแฟล็กได้อย่างไร?


131

ถ้าฉันมีตัวแปรที่ถือแฟล็ก enum ฉันจะวนซ้ำค่าบิตในตัวแปรนั้นได้หรือไม่ หรือฉันต้องใช้ Enum.GetValues ​​เพื่อวนซ้ำรอบ enum ทั้งหมดและตรวจสอบว่ามีการตั้งค่าใด


หากคุณสามารถควบคุม API ของคุณได้ให้หลีกเลี่ยงการใช้แฟล็กบิต ซึ่งแทบจะไม่เป็นการเพิ่มประสิทธิภาพที่เป็นประโยชน์ การใช้โครงสร้างกับฟิลด์ 'บูล' สาธารณะหลายฟิลด์นั้นมีความหมายเทียบเท่ากัน แต่โค้ดของคุณนั้นง่ายกว่ามาก และถ้าคุณต้องการในภายหลังคุณสามารถเปลี่ยนฟิลด์เป็นคุณสมบัติที่จัดการฟิลด์บิตภายในโดยห่อหุ้มการปรับให้เหมาะสม
Jay Bazuzi

2
ฉันเห็นว่าคุณกำลังพูดอะไรและในหลาย ๆ กรณีมันก็สมเหตุสมผล แต่ในกรณีนี้ฉันมีปัญหาเหมือนกับคำแนะนำ If ... ฉันต้องเขียนคำสั่ง If สำหรับบูลที่แตกต่างกันโหลแทน ของการใช้ foreach loop อย่างง่ายบนอาร์เรย์ (และเนื่องจากนี่เป็นส่วนหนึ่งของ DLL สาธารณะฉันจึงไม่สามารถทำสิ่งที่ลึกลับเช่นการมี

10
"โค้ดของคุณง่ายกว่ามาก" - ตรงกันข้ามโดยสิ้นเชิงหากคุณกำลังทำสิ่งอื่นนอกเหนือจากการทดสอบทีละบิต ... การดำเนินการลูปและเซ็ตแทบจะเป็นไปไม่ได้เลยเพราะฟิลด์และคุณสมบัติไม่ใช่เอนทิตีชั้นหนึ่ง
Jim Balter

2
@nawfal "หน่อย" ฉันเห็นสิ่งที่คุณทำที่นั่น
stannius

คำตอบ:


180
static IEnumerable<Enum> GetFlags(Enum input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
        if (input.HasFlag(value))
            yield return value;
}

7
โปรดทราบว่าHasFlagพร้อมใช้งานตั้งแต่. NET 4 เป็นต้นไป
Andreas Grech

3
นี่มันเยี่ยมมาก! แต่คุณสามารถทำให้ง่ายขึ้นและใช้งานง่าย เพียงแค่ยึดสิ่งนี้เป็นวิธีการขยาย: Enum.GetValues(input.GetType()).Cast<Enum>().Where(input.HasFlag); จากนั้นเพียง: myEnum.GetFLags():)
joshcomley

3
หนึ่งซับที่ยอดเยี่ยม josh แต่ก็ยังประสบปัญหาในการเลือกค่าหลายแฟล็ก (Boo) แทนที่จะเป็นค่าแฟล็กเดียวเท่านั้น (Bar, Baz) ดังในคำตอบของ Jeff ด้านบน

10
ดี - ระวังไม่มี - เช่นรายการจะไม่รวมคำตอบจากเจฟฟ์ไว้เสมอ
Ilan

1
ลายเซ็นของวิธีการควรเป็นstatic IEnumerable<Enum> GetFlags(this Enum input)
Erwin Rooijakkers

48

นี่คือวิธีแก้ปัญหาของ Linq

public static IEnumerable<Enum> GetFlags(this Enum e)
{
      return Enum.GetValues(e.GetType()).Cast<Enum>().Where(e.HasFlag);
}

7
ทำไมถึงไม่อยู่ด้านบน ?? :) ใช้.Where(v => !Equals((int)(object)v, 0) && e.HasFlag(v));ถ้าคุณมีค่าเป็นศูนย์เพื่อแสดงNone
georgiosd

สะอาดมาก ทางออกที่ดีที่สุดในความคิดของฉัน
Ryan Fiorini

@georgiosd ฉันเดาว่าการแสดงไม่ได้ดีขนาดนั้น (แต่ควรจะดีพอสำหรับงานส่วนใหญ่)
AntiHeadshot

41

ไม่มีเมธอดในตัวเพื่อรับแต่ละองค์ประกอบเท่าที่ฉันรู้ แต่นี่เป็นวิธีหนึ่งที่คุณจะได้รับ:

[Flags]
enum Items
{
    None = 0x0,
    Foo  = 0x1,
    Bar  = 0x2,
    Baz  = 0x4,
    Boo  = 0x6,
}

var value = Items.Foo | Items.Bar;
var values = value.ToString()
                  .Split(new[] { ", " }, StringSplitOptions.None)
                  .Select(v => (Items)Enum.Parse(typeof(Items), v));

// This method will always end up with the most applicable values
value = Items.Bar | Items.Baz;
values = value.ToString()
              .Split(new[] { ", " }, StringSplitOptions.None)
              .Select(v => (Items)Enum.Parse(typeof(Items), v)); // Boo

ฉันปรับสิ่งที่Enumทำภายในเพื่อสร้างสตริงเพื่อส่งคืนแฟล็กแทน คุณสามารถดูรหัสในตัวสะท้อนแสงและควรมีค่าเทียบเท่ากันมากหรือน้อย ใช้ได้ดีสำหรับกรณีการใช้งานทั่วไปที่มีค่าที่มีหลายบิต

static class EnumExtensions
{
    public static IEnumerable<Enum> GetFlags(this Enum value)
    {
        return GetFlags(value, Enum.GetValues(value.GetType()).Cast<Enum>().ToArray());
    }

    public static IEnumerable<Enum> GetIndividualFlags(this Enum value)
    {
        return GetFlags(value, GetFlagValues(value.GetType()).ToArray());
    }

    private static IEnumerable<Enum> GetFlags(Enum value, Enum[] values)
    {
        ulong bits = Convert.ToUInt64(value);
        List<Enum> results = new List<Enum>();
        for (int i = values.Length - 1; i >= 0; i--)
        {
            ulong mask = Convert.ToUInt64(values[i]);
            if (i == 0 && mask == 0L)
                break;
            if ((bits & mask) == mask)
            {
                results.Add(values[i]);
                bits -= mask;
            }
        }
        if (bits != 0L)
            return Enumerable.Empty<Enum>();
        if (Convert.ToUInt64(value) != 0L)
            return results.Reverse<Enum>();
        if (bits == Convert.ToUInt64(value) && values.Length > 0 && Convert.ToUInt64(values[0]) == 0L)
            return values.Take(1);
        return Enumerable.Empty<Enum>();
    }

    private static IEnumerable<Enum> GetFlagValues(Type enumType)
    {
        ulong flag = 0x1;
        foreach (var value in Enum.GetValues(enumType).Cast<Enum>())
        {
            ulong bits = Convert.ToUInt64(value);
            if (bits == 0L)
                //yield return value;
                continue; // skip the zero value
            while (flag < bits) flag <<= 1;
            if (flag == bits)
                yield return value;
        }
    }
}

เมธอดส่วนขยายGetIndividualFlags()รับแฟล็กทั้งหมดสำหรับแต่ละประเภท ดังนั้นค่าที่มีหลายบิตจึงถูกละไว้

var value = Items.Bar | Items.Baz;
value.GetFlags();           // Boo
value.GetIndividualFlags(); // Bar, Baz

ฉันคิดว่าจะทำการแยกสตริง แต่นั่นอาจเป็นค่าใช้จ่ายมากกว่าการวนซ้ำค่าบิตของ enum ทั้งหมด

น่าเสียดายที่การทำเช่นนั้นคุณจะต้องทดสอบค่าซ้ำซ้อน (หากไม่ต้องการ) ดูตัวอย่างที่สองของฉันก็จะให้ผลผลิตBar, BazและแทนเพียงBoo Boo
Jeff Mercado

น่าสนใจที่คุณสามารถกำจัด Boo ออกมาได้แม้ว่าส่วนนั้นจะไม่จำเป็น (และอันที่จริงเป็นความคิดที่แย่มาก :)) สำหรับสิ่งที่ฉันทำ

สิ่งนี้ดูน่าสนใจ แต่ถ้าฉันไม่เข้าใจผิดมันจะส่งคืน Boo สำหรับ enum ข้างต้นโดยที่ฉันต้องการระบุเฉพาะเวอร์ชันที่ไม่ใช่การรวมกันของค่าอื่น ๆ (เช่นค่าที่เป็นพลังของสอง) . สามารถทำได้อย่างง่ายดาย? ฉันพยายามแล้วและฉันไม่สามารถคิดวิธีง่ายๆในการระบุสิ่งนั้นได้โดยไม่ต้องใช้คณิตศาสตร์ FP

@ โรบิน: คุณพูดถูกแล้วต้นฉบับจะกลับมาBoo(ค่าที่ส่งคืนโดยใช้ToString()) ฉันได้ปรับแต่งให้อนุญาตเฉพาะแฟล็กแต่ละรายการ ดังนั้นในตัวอย่างของฉันคุณจะได้รับBarและแทนBaz Boo
Jeff Mercado

26

กลับมาในอีกไม่กี่ปีต่อมาด้วยประสบการณ์ที่มากขึ้นอีกเล็กน้อยคำตอบที่ดีที่สุดของฉันสำหรับค่าบิตเดียวเท่านั้นโดยเปลี่ยนจากบิตต่ำสุดไปยังบิตสูงสุดเป็นตัวแปรเล็กน้อยของกิจวัตรภายในของ Jeff Mercado:

public static IEnumerable<Enum> GetUniqueFlags(this Enum flags)
{
    ulong flag = 1;
    foreach (var value in Enum.GetValues(flags.GetType()).Cast<Enum>())
    {
        ulong bits = Convert.ToUInt64(value);
        while (flag < bits)
        {
            flag <<= 1;
        }

        if (flag == bits && flags.HasFlag(value))
        {
            yield return value;
        }
    }
}

ดูเหมือนว่าจะใช้งานได้และแม้จะมีการคัดค้านของฉันเมื่อหลายปีก่อนฉันใช้ HasFlag ที่นี่เนื่องจากมันชัดเจนกว่าการใช้การเปรียบเทียบแบบบิตและความแตกต่างของความเร็วนั้นไม่มีนัยสำคัญสำหรับทุกสิ่งที่ฉันจะทำ (เป็นไปได้ทั้งหมดที่พวกเขาได้ปรับปรุงความเร็วของ HasFlags ตั้งแต่นั้นมาสำหรับทั้งหมดที่ฉันรู้ ... ฉันยังไม่ได้ทดสอบ)


เพียงแค่แฟ
ล็

ขอบคุณฉันจะแก้ไข! (ฉันเพิ่งไปตรวจสอบรหัสจริงของฉันและฉันได้แก้ไขแล้วด้วยวิธีอื่น ๆ โดยการประกาศให้เป็น ulong โดยเฉพาะ)

2
นี่เป็นทางออกเดียวที่ฉันพบว่าดูเหมือนว่าจะไม่ได้รับความจริงที่ว่าหากคุณมีแฟล็กที่มีค่าเป็นศูนย์ซึ่งควรแสดงถึง "ไม่มี" คำตอบอื่น ๆ เมธอด GetFlag () จะคืนค่า YourEnum.None เป็นหนึ่งในแฟล็ก แม้ว่ามันจะไม่ได้อยู่ใน enum คุณกำลังเรียกใช้วิธีการ! ฉันได้รับรายการบันทึกที่ซ้ำกันแปลก ๆ เพราะเมธอดทำงานมากกว่าที่ฉันคาดไว้เมื่อมีชุดค่าสถานะ enum ที่ไม่ใช่ศูนย์เพียงชุดเดียว ขอขอบคุณที่สละเวลาอัปเดตและเพิ่มโซลูชันที่ยอดเยี่ยมนี้!
BrianH

yield return bits;?
Jaider

1
ฉันต้องการตัวแปร enum "ทั้งหมด" ซึ่งฉันกำหนดให้กับ ulong.MaxValue ดังนั้นบิตทั้งหมดจึงถูกตั้งค่าเป็น '1' แต่โค้ดของคุณจะวนซ้ำไม่สิ้นสุดเนื่องจากแฟล็ก <bits ไม่เคยประเมินค่าเป็นจริง (แฟล็กลูปเป็นค่าลบแล้วค้างที่ 0)
Haighstrom

15

ออกจากวิธีการของ @ Greg แต่เพิ่มคุณสมบัติใหม่จาก C # 7.3 Enumข้อ จำกัด :

public static IEnumerable<T> GetUniqueFlags<T>(this Enum flags)
    where T : Enum    // New constraint for C# 7.3
{
    foreach (Enum value in Enum.GetValues(flags.GetType()))
        if (flags.HasFlag(value))
            yield return (T)value;
}

ข้อ จำกัด ใหม่ที่ช่วยให้นี้จะเป็นวิธีขยายโดยไม่ต้องโยนผ่าน(int)(object)eและฉันสามารถใช้HasFlagวิธีการและโยนโดยตรงไปจากTvalue

C # 7.3 ยังเพิ่มข้อ จำกัด สำหรับค่าเดลาเกตและunmanaged.


4
คุณอาจต้องการให้flagsพารามิเตอร์เป็นประเภททั่วไปTด้วยมิฉะนั้นคุณจะต้องระบุประเภท enum อย่างชัดเจนทุกครั้งที่เรียกใช้
Ray

11

+1 สำหรับคำตอบโดย @ RobinHood70 ฉันพบว่าวิธีการทั่วไปนั้นสะดวกสำหรับฉัน

public static IEnumerable<T> GetUniqueFlags<T>(this Enum flags)
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("The generic type parameter must be an Enum.");

    if (flags.GetType() != typeof(T))
        throw new ArgumentException("The generic type parameter does not match the target type.");

    ulong flag = 1;
    foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
    {
        ulong bits = Convert.ToUInt64(value);
        while (flag < bits)
        {
            flag <<= 1;
        }

        if (flag == bits && flags.HasFlag(value as Enum))
        {
            yield return value;
        }
    }
}

แก้ไข และ +1 สำหรับ @AustinWBryan เพื่อนำ C # 7.3 เข้าสู่พื้นที่โซลูชัน

public static IEnumerable<T> GetUniqueFlags<T>(this T flags) where T : Enum
{
    ulong flag = 1;
    foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
    {
        ulong bits = Convert.ToUInt64(value);
        while (flag < bits)
        {
            flag <<= 1;
        }

        if (flag == bits && flags.HasFlag(value as Enum))
        {
            yield return value;
        }
    }
}

3

คุณไม่จำเป็นต้องวนซ้ำค่าทั้งหมด เพียงตรวจสอบแฟล็กเฉพาะของคุณดังนี้:

if((myVar & FlagsEnum.Flag1) == FlagsEnum.Flag1) 
{
   //do something...
}

หรือ (ตามที่pstrjdsกล่าวในความคิดเห็น) คุณสามารถตรวจสอบการใช้งานได้เช่น:

if(myVar.HasFlag(FlagsEnum.Flag1))
{
   //do something...
}

5
หากคุณใช้. Net 4.0 มีวิธีการขยาย HasFlag ที่คุณสามารถใช้เพื่อทำสิ่งเดียวกัน: myVar.HasFlag (FlagsEnum.Flag1)
pstrjds

1
หากโปรแกรมเมอร์ไม่เข้าใจการทำงานในระดับบิตและพวกเขาควรรวบรวมและหาอาชีพใหม่
Ed S.

2
@Ed: จริง แต่ HasFlag จะดีกว่าเมื่อคุณอ่านโค้ดอีกครั้ง ... (อาจจะหลังจากเดือนหรือหลายปี)
Dr TJ

4
@Ed Swangren: มันเกี่ยวกับการทำให้โค้ดอ่านง่ายขึ้นและใช้งานได้น้อยลงไม่จำเป็นต้องเป็นเพราะการใช้การดำเนินการระดับบิตนั้น "ยาก"
Jeff Mercado

2
HasFlag ช้ามาก ลองวนซ้ำขนาดใหญ่โดยใช้ HasFlag เทียบกับ bit-masking แล้วคุณจะสังเกตเห็นความแตกต่างอย่างมาก

3

สิ่งที่ฉันทำคือเปลี่ยนแนวทางของฉันแทนที่จะพิมพ์พารามิเตอร์อินพุตของเมธอดเป็นenumประเภทฉันพิมพ์เป็นอาร์เรย์ของenumประเภท ( MyEnum[] myEnums) วิธีนี้ฉันจะวนซ้ำผ่านอาร์เรย์ด้วยคำสั่งสวิตช์ภายในลูป


2

ไม่พอใจกับคำตอบข้างต้นแม้ว่าจะเป็นการเริ่มต้นก็ตาม

หลังจากรวบรวมแหล่งข้อมูลต่างๆที่นี่:
โปสเตอร์ก่อนหน้าใน
โครงการSO QnA Code ของเธรดนี้Enum Flags ตรวจสอบโพสต์
Great Enum <T> Utility

ฉันสร้างสิ่งนี้ขึ้นมาเพื่อบอกให้ฉันรู้ว่าคุณคิดอย่างไร
พารามิเตอร์::
bool checkZeroบอกให้อนุญาต0เป็นค่าแฟล็ก โดยค่าเริ่มต้นinput = 0จะคืนค่าว่างเปล่า
bool checkFlags: บอกให้ตรวจสอบว่าEnumมีการตกแต่งด้วย[Flags]แอตทริบิวต์หรือไม่
PS ตอนนี้ฉันไม่มีเวลาหาcheckCombinators = falsealg ซึ่งจะบังคับให้ไม่สนใจค่า enum ใด ๆ ที่เป็นชุดค่าผสมของบิต

    public static IEnumerable<TEnum> GetFlags<TEnum>(this TEnum input, bool checkZero = false, bool checkFlags = true, bool checkCombinators = true)
    {
        Type enumType = typeof(TEnum);
        if (!enumType.IsEnum)
            yield break;

        ulong setBits = Convert.ToUInt64(input);
        // if no flags are set, return empty
        if (!checkZero && (0 == setBits))
            yield break;

        // if it's not a flag enum, return empty
        if (checkFlags && !input.GetType().IsDefined(typeof(FlagsAttribute), false))
            yield break;

        if (checkCombinators)
        {
            // check each enum value mask if it is in input bits
            foreach (TEnum value in Enum<TEnum>.GetValues())
            {
                ulong valMask = Convert.ToUInt64(value);

                if ((setBits & valMask) == valMask)
                    yield return value;
            }
        }
        else
        {
            // check each enum value mask if it is in input bits
            foreach (TEnum value in Enum <TEnum>.GetValues())
            {
                ulong valMask = Convert.ToUInt64(value);

                if ((setBits & valMask) == valMask)
                    yield return value;
            }
        }

    }

สิ่งนี้ใช้ประโยชน์จาก Helper Class Enum <T>ที่ฉันอัปเดตเพื่อใช้yield returnสำหรับGetValues:

public static class Enum<TEnum>
{
    public static TEnum Parse(string value)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), value);
    }

    public static IEnumerable<TEnum> GetValues()   
    {
        foreach (object value in Enum.GetValues(typeof(TEnum)))
            yield return ((TEnum)value);
    }
}  

สุดท้ายนี่คือตัวอย่างการใช้งาน:

    private List<CountType> GetCountTypes(CountType countTypes)
    {
        List<CountType> cts = new List<CountType>();

        foreach (var ct in countTypes.GetFlags())
            cts.Add(ct);

        return cts;
    }

ขออภัยไม่มีเวลาดูโครงการนี้มาหลายวันแล้ว ฉันจะติดต่อกลับเมื่อได้ตรวจสอบรหัสของคุณให้ดีขึ้นแล้ว

4
โปรดทราบว่ามีข้อบกพร่องในรหัสนั้น รหัสในทั้งสองสาขาของคำสั่ง if (checkCombinators) เหมือนกัน นอกจากนี้อาจไม่ใช่ข้อผิดพลาด แต่คาดไม่ถึงก็คือถ้าคุณมีค่า enum ที่ประกาศเป็น 0 ค่านั้นจะถูกส่งคืนในคอลเล็กชันเสมอ ดูเหมือนว่าควรส่งคืนก็ต่อเมื่อ checkZero เป็นจริงและไม่มีการตั้งค่าสถานะอื่น ๆ
dhochee

@dhochee ฉันเห็นด้วย. หรือรหัสค่อนข้างดี แต่ข้อโต้แย้งทำให้สับสน
หลัง

2

จากคำตอบของ Greg ข้างต้นสิ่งนี้ยังดูแลกรณีที่คุณมีค่า 0 ใน enum ของคุณเช่น None = 0 ในกรณีนี้ไม่ควรวนซ้ำเกินค่านั้น

public static IEnumerable<Enum> ToEnumerable(this Enum input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
        if (input.HasFlag(value) && Convert.ToInt64(value) != 0)
            yield return value;
}

ใครจะรู้วิธีปรับปรุงสิ่งนี้ให้ดียิ่งขึ้นเพื่อที่จะสามารถจัดการกับกรณีที่แฟล็กทั้งหมดใน enum ถูกตั้งค่าด้วยวิธีที่ชาญฉลาดที่สามารถจัดการประเภท enum ที่อยู่ข้างใต้ทั้งหมดและกรณีของ All = ~ 0 และ All = EnumValue1 | EnumValue2 | EnumValue3 | ...


1

คุณสามารถใช้ Iterator จาก Enum เริ่มต้นจากรหัส MSDN:

public class DaysOfTheWeek : System.Collections.IEnumerable
{
    int[] dayflag = { 1, 2, 4, 8, 16, 32, 64 };
    string[] days = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    public string value { get; set; }

    public System.Collections.IEnumerator GetEnumerator()
    {
        for (int i = 0; i < days.Length; i++)
        {
            if value >> i & 1 == dayflag[i] {
                yield return days[i];
            }
        }
    }
}

ยังไม่ผ่านการทดสอบดังนั้นหากฉันทำผิดพลาดอย่าลังเลที่จะโทรหาฉัน (เห็นได้ชัดว่าไม่ใช่ re-entrant) คุณต้องกำหนดค่าไว้ล่วงหน้าหรือแยกออกเป็นฟังก์ชันอื่นที่ใช้ enum.dayflag และ enum.days คุณอาจจะไปที่ไหนสักแห่งด้วยโครงร่าง


0

อาจเป็นเช่นเดียวกับรหัสต่อไปนี้:

public static string GetEnumString(MyEnum inEnumValue)
{
    StringBuilder sb = new StringBuilder();

    foreach (MyEnum e in Enum.GetValues(typeof(MyEnum )))
    {
        if ((e & inEnumValue) != 0)
        {
           sb.Append(e.ToString());
           sb.Append(", ");
        }
    }

   return sb.ToString().Trim().TrimEnd(',');
}

จะเข้าไปข้างในก็ต่อเมื่อมีค่า enum อยู่ในค่าเท่านั้น


0

คำตอบทั้งหมดทำงานได้ดีกับแฟล็กธรรมดาคุณอาจจะมีปัญหาเมื่อรวมแฟล็กเข้าด้วยกัน

[Flags]
enum Food
{
  None=0
  Bread=1,
  Pasta=2,
  Apples=4,
  Banana=8,
  WithGluten=Bread|Pasta,
  Fruits = Apples | Banana,
}

อาจต้องเพิ่มการตรวจสอบเพื่อทดสอบว่าค่า enum ของตัวเองเป็นชุดค่าผสมหรือไม่ คุณอาจต้องการบางอย่างเช่นที่Henk van Boeijenโพสต์ไว้ที่นี่ เพื่อให้ครอบคลุมความต้องการของคุณ (คุณต้องเลื่อนลงเล็กน้อย)


0

วิธีการขยายโดยใช้ข้อ จำกัด Enum และ generics ใหม่เพื่อป้องกันการหล่อ:

public static class EnumExtensions
{
    public static T[] GetFlags<T>(this T flagsEnumValue) where T : Enum
    {
        return Enum
            .GetValues(typeof(T))
            .Cast<T>()
            .Where(e => flagsEnumValue.HasFlag(e))
            .ToArray();
    }
}

-1

คุณสามารถทำได้โดยตรงโดยการแปลงเป็น int แต่คุณจะตรวจสอบประเภทหลวม ฉันคิดว่าวิธีที่ดีที่สุดคือใช้สิ่งที่คล้ายกับโจทย์ของฉัน รักษาประเภทที่เหมาะสมตลอดทาง ไม่จำเป็นต้องแปลง มันไม่สมบูรณ์แบบเนื่องจากการชกมวยซึ่งจะเพิ่มประสิทธิภาพการตีเล็กน้อย

ไม่เพอร์เฟกต์ (หมวย) แต่ทำงานแบบไม่มีคำเตือน ...

/// <summary>
/// Return an enumerators of input flag(s)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(this T input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
    {
        if ((int) (object) value != 0) // Just in case somebody has defined an enum with 0.
        {
            if (((Enum) (object) input).HasFlag(value))
                yield return (T) (object) value;
        }
    }
}

การใช้งาน:

    FileAttributes att = FileAttributes.Normal | FileAttributes.Compressed;
    foreach (FileAttributes fa in att.GetFlags())
    {
        ...
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.