Bagaimana Anda meneruskan beberapa nilai enum di C #?

117

Kadang-kadang ketika membaca kode C # orang lain saya melihat metode yang akan menerima beberapa nilai enum dalam satu parameter. Saya selalu berpikir itu rapi, tetapi tidak pernah memeriksanya.

Nah, sekarang saya pikir saya mungkin membutuhkannya, tetapi tidak tahu bagaimana caranya

  1. mengatur tanda tangan metode untuk menerima ini
  2. bekerja dengan nilai-nilai dalam metode
  3. tentukan enumnya

untuk mencapai hal semacam ini.


Dalam situasi khusus saya, saya ingin menggunakan System.DayOfWeek, yang didefinisikan sebagai:

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

Saya ingin dapat meneruskan satu atau lebih nilai DayOfWeek ke metode saya. Apakah saya dapat menggunakan enum khusus ini sebagaimana adanya? Bagaimana saya melakukan 3 hal yang tercantum di atas?

Ronnie Overby
sumber
1
Seperti disebutkan di bawah, Anda dapat menggunakan enum Flags. Anda mungkin ingin memeriksa Seluk beluk C # enum , yang berisi lebih banyak informasi tentang bekerja dengan enum Flags.
ChaseMedallion

Jawaban:

181

Saat Anda menentukan enum, cukup atributkan dengan [Flags], setel nilai ke pangkat dua, dan cara ini akan berfungsi.

Tidak ada lagi yang berubah, selain meneruskan beberapa nilai ke dalam suatu fungsi.

Sebagai contoh:

[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);
}

Untuk lebih jelasnya, lihat dokumentasi MSDN tentang Jenis Enumerasi .


Edit sebagai tanggapan atas penambahan pertanyaan.

Anda tidak akan dapat menggunakan enum itu sebagaimana adanya, kecuali Anda ingin melakukan sesuatu seperti meneruskannya sebagai array / collection / params array. Itu akan membiarkan Anda memberikan banyak nilai. Sintaks flags membutuhkan Enum untuk dispesifikasikan sebagai flag (atau untuk mengubah bahasa dengan cara yang tidak didesain).

Reed Copsey
sumber
9
Saya pikir jika Anda ingin ini berfungsi, nilai perlu didefinisikan sebagai pangkat dua, satu bit untuk setiap nilai. Apa yang terjadi adalah Anda meneruskan bitwise ATAU dari nilai di parameter, yang dapat Anda periksa menggunakan operasi bitwise AND. Jika Anda tidak berhati-hati dalam menentukan nilai, misalnya, 1,2,4,8 dll, Anda akan mendapat masalah.
Denis Troller
1
Hanya mengatur atribut Flags saja tidak bekerja secara otomatis. Saya baru mencobanya.
Richard Anthony Hein
1
Anda benar, dan saya menghapus informasi yang salah. Memperbaiki kode Reed juga untuknya.
Matthew Scharley
@monoksida: Saya memperbaikinya pada saat yang sama - maaf karena menimpa hasil edit Anda.
Reed Copsey
2
Tidak masalah ... Saya masih lebih suka menggunakan hex untuk nilai bendera seperti itu, tampaknya lebih jelas bagi saya, tetapi masing-masing untuk miliknya sendiri.
Matthew Scharley
78

Saya pikir solusi yang lebih elegan adalah dengan menggunakan 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);
    }
Tillito
sumber
Ada hal penting lain yang perlu diketahui, jika Anda melakukannya dengan cara ini: Ini menambahkan lebih banyak fleksibilitas saat Anda perlu mengisi enum Anda secara dinamis. Misalnya: Jika Anda menggunakan kotak centang untuk menentukan hari, di mana Anda ingin program Anda dijalankan, dan Anda akan mencoba melakukannya dengan cara yang dilakukan di atas, kode tidak akan terbaca. Jadi sebagai gantinya Anda dapat melakukannya dengan cara ini: ... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN
25

Aku mendukung jawaban Reed. Namun, saat membuat enum, Anda harus menentukan nilai untuk setiap anggota enum sehingga membuat semacam bidang bit. Sebagai contoh:

[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.
}
Yakub
sumber
1
Ini akan membantu Anda jika Anda perlu memeriksa nilai DaysOfWeek, misalnya jika Anda membaca nilai yang disimpan dalam database. Juga, ini menyediakan dokumentasi yang lebih baik untuk pemrogram lain, karena beberapa hari menghitung dalam seminggu mulai dari Senin, bukan Minggu.
Jacob
3
Untuk kejelasan dan pemeliharaan, saya akan menulis enum 'Semua' Anda sebagai "Minggu | Senin | Selasa | Rabu | Kamis | Jumat | Sabtu" ... dan menggunakan notasi serupa untuk 'Hari Kerja' dan 'Akhir Pekan'.
Robert Cartaino
Ini bagus jika Anda ingin membuat enum sendiri, tetapi untuk menjawab pertanyaan Anda tidak dapat mengubah enum DaysOfWeek yang ada
Robert Paulson
2
Bukan "mungkin ingin" ... Anda HARUS. Perbandingan bitwise membutuhkannya. Membiarkan nilai tidak ditentukan tidak akan berfungsi.
Richard Anthony Hein
11

Dalam situasi khusus saya, saya ingin menggunakan System.DayOfWeek

Anda tidak dapat menggunakan System.DayOfWeek sebagai [Flags]enumerasi karena Anda tidak memiliki kendali atasnya. Jika Anda ingin memiliki metode yang menerima beberapa DayOfWeekmaka Anda harus menggunakan paramskata kunci

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 );

Jika tidak, Anda dapat membuat [Flags]enumerasi Anda sendiri seperti yang dijelaskan oleh banyak responden lain dan menggunakan perbandingan bitwise.

Robert Paulson
sumber
2
Saya tidak tahu mengapa saya tidak memikirkan params. Itu akan sangat berguna untuk menggunakan enum yang bukan bitfield.
Ronnie Overby
10
[Flags]
public enum DaysOfWeek
{
  Mon = 1,
  Tue = 2,
  Wed = 4,
  Thur = 8,
  Fri = 16,
  Sat = 32,
  Sun = 64
}

Anda harus menentukan angkanya, dan menaikkannya seperti ini karena ini menyimpan nilai dengan cara yang sedikit bijak.

Kemudian tentukan saja metode Anda untuk mengambil enum ini

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

dan menyebutnya lakukan sesuatu seperti

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

Untuk memeriksa apakah salah satu nilai enum disertakan, periksa menggunakan operasi bitwise seperti

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
  }
}
Tetraneutron
sumber
Tidak menjawab pertanyaan itu. "Dalam situasi khusus saya, saya ingin menggunakan System.DayOfWeek"
Robert Paulson
Tapi itu persis apa yang saya cari. Jadi terima kasih.
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
    }

panggil metode dalam format ini

MethodName (DaysOfWeek.Tuesday | DaysOfWeek.Thursday);

Menerapkan metode EnumToArray untuk meneruskan opsi

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();
        }
Rony
sumber
Tidak menjawab pertanyaan itu. "Dalam situasi khusus saya, saya ingin menggunakan System.DayOfWeek"
Robert Paulson
Terima kasih, Robert, tetapi Anda benar-benar tidak perlu menunjukkan hal ini di setiap jawaban.
Ronnie Overby
@Ronnie - Bukan salah saya bahwa ada begitu banyak jawaban yang hampir duplikat yang sebenarnya tidak menjawab pertanyaan itu.
Robert Paulson
@Rony - enum ToString () dan Enum.Parse () akan mengeluarkan / mengurai dengan benar enumerasi [Flags] (selama Anda berhati-hati dengan versi enumerasi tentunya)
Robert Paulson
@Robert - Saya rasa tidak ada yang menyalahkan Anda. Biarkan suara yang berbicara.
Ronnie Overby
3

Tandai enum Anda dengan atribut [Flags]. Juga pastikan bahwa semua nilai Anda saling eksklusif (dua nilai tidak dapat berjumlah sama dengan yang lain) seperti 1,2,4,8,16,32,64 dalam kasus Anda

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

Saat Anda memiliki metode yang menerima enum DayOfWeek, gunakan bitwise atau operator (|) untuk menggunakan banyak anggota secara bersamaan. Sebagai contoh:

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

Untuk memeriksa apakah parameter berisi anggota tertentu, gunakan bitwise dan operator (&) dengan anggota yang Anda periksa.

if(arg & DayOfWeek.Sunday == DayOfWeek.Sunday)
Console.WriteLine("Contains Sunday");
statenjason
sumber
Tidak menjawab pertanyaan itu. "Dalam situasi khusus saya, saya ingin menggunakan System.DayOfWeek"
Robert Paulson
2

Reed Copsey benar dan saya akan menambahkan ke posting asli jika saya bisa, tetapi saya tidak bisa jadi saya harus membalas sebagai gantinya.

Berbahaya hanya menggunakan [Bendera] di enum lama mana pun. Saya percaya Anda harus secara eksplisit mengubah nilai enum menjadi pangkat dua saat menggunakan bendera, untuk menghindari bentrokan nilai. Lihat pedoman untuk FlagsAttribute dan Enum .

Dan
sumber
0

Dengan bantuan jawaban yang diposting dan ini:

  1. FlagsAttribute Class (Lihat perbandingan antara menggunakan dan tidak menggunakan atribut [Flags])
  2. Atribut Bendera Enum

Saya merasa saya memahaminya dengan cukup baik.

Terima kasih.

Ronnie Overby
sumber
-3

Sesuatu seperti ini seharusnya menunjukkan apa yang Anda cari:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
Andrew Siemer
sumber