คุณส่งผ่านค่า enum หลายค่าใน C # ได้อย่างไร


117

บางครั้งเมื่ออ่านรหัส C # ของผู้อื่นฉันเห็นวิธีการที่จะยอมรับค่า enum หลายค่าในพารามิเตอร์เดียว ฉันคิดเสมอว่ามันดูเรียบร้อย แต่ไม่เคยมองเข้าไปในนั้น

ตอนนี้ฉันคิดว่าฉันอาจต้องการมัน แต่ไม่รู้จะทำอย่างไร

  1. ตั้งค่าลายเซ็นวิธีการเพื่อยอมรับสิ่งนี้
  2. ทำงานกับค่าในวิธีการ
  3. กำหนด enum

เพื่อให้บรรลุสิ่งนี้


ในสถานการณ์เฉพาะของฉันฉันต้องการใช้ System.DayOfWeek ซึ่งกำหนดเป็น:

[Serializable]
[ComVisible(true)]
public enum DayOfWeek
{ 
    Sunday = 0,   
    Monday = 1,   
    Tuesday = 2,   
    Wednesday = 3,   
    Thursday = 4,   
    Friday = 5,    
    Saturday = 6
}

ฉันต้องการส่งผ่านค่า DayOfWeek อย่างน้อยหนึ่งค่าไปยังเมธอดของฉัน ฉันจะสามารถใช้ enum นี้ตามที่เป็นอยู่ได้หรือไม่? ฉันจะทำ 3 สิ่งที่ระบุไว้ข้างต้นได้อย่างไร?


1
ดังที่กล่าวไว้ด้านล่างคุณสามารถใช้ Flags enum คุณอาจต้องการตรวจสอบข้อมูลเชิงลึกของ C # enumsซึ่งมีข้อมูลเพิ่มเติมเกี่ยวกับการทำงานกับ Flags enums
ChaseMedallion

คำตอบ:


181

เมื่อคุณกำหนด enum เพียงแค่ระบุด้วย [Flags] ตั้งค่าเป็นพาวเวอร์สองและจะทำงานในลักษณะนี้

ไม่มีอะไรเปลี่ยนแปลงนอกเหนือจากการส่งผ่านค่าหลายค่าไปยังฟังก์ชัน

ตัวอย่างเช่น:

[Flags]
enum DaysOfWeek
{
   Sunday = 1,
   Monday = 2,
   Tuesday = 4,
   Wednesday = 8,
   Thursday = 16,
   Friday = 32,
   Saturday = 64
}

public void RunOnDays(DaysOfWeek days)
{
   bool isTuesdaySet = (days & DaysOfWeek.Tuesday) == DaysOfWeek.Tuesday;

   if (isTuesdaySet)
      //...
   // Do your work here..
}

public void CallMethodWithTuesdayAndThursday()
{
    this.RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
}

สำหรับรายละเอียดเพิ่มเติมโปรดดูเอกสาร MSDN ในประเภทการแจงนับ


แก้ไขเพื่อตอบคำถามเพิ่มเติม

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


9
ฉันคิดว่าถ้าคุณต้องการให้สิ่งนี้ทำงานได้ค่าต่างๆจะต้องถูกกำหนดเป็นพาวเวอร์ของสองบิตเดียวสำหรับแต่ละค่า สิ่งที่เกิดขึ้นคือคุณส่งผ่านบิตหรือของค่าในพารามิเตอร์ซึ่งคุณสามารถตรวจสอบได้โดยใช้การดำเนินการแบบบิต AND หากคุณไม่ดูแลการกำหนดค่าเช่น 1,2,4,8 เป็นต้นคุณจะมีปัญหา
Denis Troller

1
การตั้งค่าแอตทริบิวต์ Flags เพียงอย่างเดียวไม่ทำงานโดยอัตโนมัติ ผมเพิ่งลองทำ
Richard Anthony Hein

1
คุณพูดถูกและฉันลบข้อมูลที่ผิด แก้ไขรหัสของ Reed ด้วยสำหรับเขา
Matthew Scharley

@monoxide: ฉันแก้ไขไปพร้อมกัน - ขออภัยที่ลบล้างการแก้ไขของคุณ
Reed Copsey

2
ไม่มีปัญหา ... ฉันยังชอบใช้ฐานสิบหกสำหรับค่าแฟล็กแบบนั้นดูเหมือนจะชัดเจนกว่าสำหรับฉัน แต่เป็นของเขาเอง
Matthew Scharley

78

ฉันคิดว่าวิธีแก้ปัญหาที่หรูหรากว่าคือการใช้ HasFlag ():

    [Flags]
    public enum DaysOfWeek
    {
        Sunday = 1,
        Monday = 2,
        Tuesday = 4,
        Wednesday = 8,
        Thursday = 16,
        Friday = 32,
        Saturday = 64
    }

    public void RunOnDays(DaysOfWeek days)
    {
        bool isTuesdaySet = days.HasFlag(DaysOfWeek.Tuesday);

        if (isTuesdaySet)
        {
            //...
        }
    }

    public void CallMethodWithTuesdayAndThursday()
    {
        RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
    }

มีสิ่งสำคัญอีกอย่างที่ควรทราบหากคุณทำด้วยวิธีนี้: จะเพิ่มความยืดหยุ่นมากขึ้นเมื่อคุณต้องการเติม enum แบบไดนามิก เช่น: หากคุณใช้ช่องทำเครื่องหมายเพื่อกำหนดวันที่คุณต้องการให้โปรแกรมของคุณทำงานและคุณจะพยายามทำสิ่งนี้ให้สำเร็จตามวิธีที่ทำไว้ข้างต้นโค้ดจะไม่สามารถอ่านได้ ดังนั้นแทนที่จะทำแบบนี้: ... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN

25

ฉันสองคำตอบของรีด อย่างไรก็ตามเมื่อสร้าง enum คุณต้องระบุค่าสำหรับสมาชิก enum แต่ละตัวเพื่อสร้างฟิลด์บิต ตัวอย่างเช่น:

[Flags]
public enum DaysOfWeek
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64,

    None = 0,
    All = Weekdays | Weekend,
    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekend = Sunday | Saturday,
    // etc.
}

1
มันจะช่วยคุณได้หากคุณต้องการตรวจสอบค่า DaysOfWeek เช่นหากคุณกำลังอ่านค่าที่เก็บไว้ในฐานข้อมูล นอกจากนี้ยังจัดเตรียมเอกสารที่ดีกว่าให้กับโปรแกรมเมอร์คนอื่น ๆ เนื่องจากบางวันในสัปดาห์จะเริ่มตั้งแต่วันจันทร์แทนที่จะเป็นวันอาทิตย์
Jacob

3
เพื่อความชัดเจนและการบำรุงรักษาฉันจะเขียน enum "ทั้งหมด" ของคุณว่า "วันอาทิตย์ | วันจันทร์ | วันอังคาร | วันพุธ | วันพฤหัสบดี | วันศุกร์ | วันเสาร์" ... และใช้สัญลักษณ์ที่คล้ายกันสำหรับ 'วันธรรมดา' และ 'วันหยุดสุดสัปดาห์'
Robert Cartaino

นี่เป็นเรื่องปกติถ้าคุณต้องการสร้าง enum ของคุณเอง แต่เพื่อตอบคำถามคุณไม่สามารถแก้ไข DaysOfWeek enum ที่มีอยู่ได้
Robert Paulson

2
ไม่ใช่ "อาจต้องการ" ... คุณต้อง ต้องมีการเปรียบเทียบ Bitwise การปล่อยให้ค่าที่ไม่ระบุจะใช้ไม่ได้
Richard Anthony Hein

11

ในสถานการณ์เฉพาะของฉันฉันต้องการใช้ System.DayOfWeek

คุณไม่สามารถใช้ System.DayOfWeek เป็นการ[Flags]แจงนับเนื่องจากคุณไม่สามารถควบคุมได้ หากคุณต้องการมีวิธีการที่ยอมรับหลายDayOfWeekคุณจะต้องใช้paramsคำหลัก

void SetDays(params DayOfWeek[] daysToSet)
{
    if (daysToSet == null || !daysToSet.Any())
        throw new ArgumentNullException("daysToSet");

    foreach (DayOfWeek day in daysToSet)
    {
        // if( day == DayOfWeek.Monday ) etc ....
    }
}

SetDays( DayOfWeek.Monday, DayOfWeek.Sunday );

มิฉะนั้นคุณสามารถสร้างการ[Flags]แจงนับของคุณเองตามที่ระบุไว้โดยผู้ตอบคำถามอื่น ๆ และใช้การเปรียบเทียบแบบบิต


2
ไม่รู้ทำไมไม่นึกถึงพารามส์ ซึ่งน่าจะมีประโยชน์มากสำหรับการใช้ enums ที่ไม่ใช่ bitfields
Ronnie Overby

10
[Flags]
public enum DaysOfWeek
{
  Mon = 1,
  Tue = 2,
  Wed = 4,
  Thur = 8,
  Fri = 16,
  Sat = 32,
  Sun = 64
}

คุณต้องระบุตัวเลขและเพิ่มขึ้นเช่นนี้เนื่องจากเป็นการจัดเก็บค่าในรูปแบบบิต

จากนั้นกำหนดวิธีการของคุณเพื่อใช้ enum นี้

public void DoSomething(DaysOfWeek day)
{
  ...
}

และเรียกว่าทำสิ่งที่ชอบ

DoSomething(DaysOfWeek.Mon | DaysOfWeek.Tue) // Both Monday and Tuesday

หากต้องการตรวจสอบว่ามีค่า enum อย่างใดอย่างหนึ่งให้ตรวจสอบโดยใช้การดำเนินการแบบบิตเช่น

public void DoSomething(DaysOfWeek day)
{
  if ((day & DaysOfWeek.Mon) == DaysOfWeek.Mon) // Does a bitwise and then compares it to Mondays enum value
  {
    // Monday was passed in
  }
}

ไม่ตอบคำถาม "ในสถานการณ์เฉพาะของฉันฉันต้องการใช้ System.DayOfWeek"
Robert Paulson

แต่มันเป็นสิ่งที่ฉันมองหา ขอบคุณมาก
Tillito

3
[Flags]
    public enum DaysOfWeek{


        Sunday = 1 << 0,
        Monday = 1 << 1,
        Tuesday = 1 << 2,
        Wednesday = 1 << 3,
        Thursday = 1 << 4,
        Friday =  1 << 5,
        Saturday =  1 << 6
    }

เรียกใช้เมธอดในรูปแบบนี้

MethodName (DaysOfWeek.T Tuesday | DaysOfWeek.Th Thursday);

ใช้เมธอด EnumToArray เพื่อส่งผ่านตัวเลือก

private static void AddEntryToList(DaysOfWeek days, DaysOfWeek match, List<string> dayList, string entryText) {
            if ((days& match) != 0) {
                dayList.Add(entryText);
            }
        }

        internal static string[] EnumToArray(DaysOfWeek days) {
            List<string> verbList = new List<string>();

            AddEntryToList(days, HttpVerbs.Sunday, dayList, "Sunday");
            AddEntryToList(days, HttpVerbs.Monday , dayList, "Monday ");
            ...

            return dayList.ToArray();
        }

ไม่ตอบคำถาม "ในสถานการณ์เฉพาะของฉันฉันต้องการใช้ System.DayOfWeek"
Robert Paulson

ขอบคุณโรเบิร์ต แต่คุณไม่จำเป็นต้องชี้ให้เห็นในทุกคำตอบ
Ronnie Overby

@ รอนนี่ - แทบจะเป็นความผิดของฉันที่มีคำตอบที่ใกล้เคียงกันมากมายที่ไม่ได้ตอบคำถามจริงๆ
Robert Paulson

@Rony - enums ToString () และ Enum.Parse () จะแสดงผล / แยกวิเคราะห์การแจงนับ [Flags] อย่างถูกต้อง (ตราบเท่าที่คุณระมัดระวังในการกำหนดเวอร์ชันการแจงนับ)
Robert Paulson

@ โรเบิร์ต - ฉันไม่คิดว่าใครจะตำหนิคุณ เพียงแค่ให้คะแนนทำการพูดคุย
Ronnie Overby

3

ทำเครื่องหมาย enum ของคุณด้วยแอตทริบิวต์ [Flags] ตรวจสอบให้แน่ใจว่าค่าทั้งหมดของคุณไม่สามารถรวมกันได้ (สองค่าไม่สามารถรวมกันได้) เช่น 1,2,4,8,16,32,64 ในกรณีของคุณ

[Flags]
public enum DayOfWeek
{ 
Sunday = 1,   
Monday = 2,   
Tuesday = 4,   
Wednesday = 8,   
Thursday = 16,   
Friday = 32,    
Saturday = 64
}

เมื่อคุณมีวิธีการที่ยอมรับ DayOfWeek enum ให้ใช้ bitwise หรือตัวดำเนินการ (|) เพื่อใช้สมาชิกหลายคนร่วมกัน ตัวอย่างเช่น:

MyMethod(DayOfWeek.Sunday|DayOfWeek.Tuesday|DayOfWeek.Friday)

ในการตรวจสอบว่าพารามิเตอร์มีสมาชิกเฉพาะหรือไม่ให้ใช้บิตและตัวดำเนินการ (&) กับสมาชิกที่คุณกำลังตรวจสอบ

if(arg & DayOfWeek.Sunday == DayOfWeek.Sunday)
Console.WriteLine("Contains Sunday");

ไม่ตอบคำถาม "ในสถานการณ์เฉพาะของฉันฉันต้องการใช้ System.DayOfWeek"
Robert Paulson

2

Reed Copsey ถูกต้องและฉันจะเพิ่มในโพสต์ต้นฉบับถ้าทำได้ แต่ทำไม่ได้ฉันจึงต้องตอบกลับแทน

มันอันตรายที่จะใช้ [Flags] กับ enum เก่า ๆ ฉันเชื่อว่าคุณต้องเปลี่ยนค่า enum เป็นพลังของสองอย่างชัดเจนเมื่อใช้แฟล็กเพื่อหลีกเลี่ยงการปะทะกันของค่า ดูแนวทางในการ FlagsAttribute และ Enum


0

ด้วยความช่วยเหลือของคำตอบที่โพสต์และสิ่งเหล่านี้:

  1. FlagsAttribute Class (ดูเปรียบเทียบการใช้และไม่ใช้แอตทริบิวต์ [Flags])
  2. Enum Flags แอตทริบิวต์

ฉันรู้สึกว่าฉันเข้าใจดีทีเดียว

ขอบคุณ


-3

บางสิ่งในลักษณะนี้ควรแสดงสิ่งที่คุณกำลังมองหา:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.