C # 'da birden çok enum değerini nasıl iletirsiniz?


117

Bazen başkalarının C # kodunu okurken, tek bir parametrede birden çok enum değerini kabul edecek bir yöntem görüyorum. Her zaman güzel olduğunu düşünmüşümdür, ama hiç bakmadım.

Şimdi sanırım buna ihtiyacım olabilir ama nasıl yapacağımı bilmiyorum

  1. bunu kabul etmek için yöntem imzasını ayarlayın
  2. yöntemdeki değerlerle çalışmak
  3. numaralandırmayı tanımla

bu tür şeyleri başarmak için.


Benim özel durumumda, şu şekilde tanımlanan System.DayOfWeek'i kullanmak istiyorum:

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

Metoduma bir veya daha fazla Haftanın Günü değerini geçirebilmek istiyorum. Bu özel sıralamayı olduğu gibi kullanabilecek miyim? Yukarıda listelenen 3 şeyi nasıl yaparım?


1
Aşağıda belirtildiği gibi, bir Bayrak listesi kullanabilirsiniz. Bayrak numaralandırmaları ile çalışma hakkında daha fazla bilgi içeren C # numaralandırmalarının giriş ve çıkışlarına göz atmak isteyebilirsiniz .
ChaseMedallion

Yanıtlar:


181

Numaralandırmayı tanımladığınızda, onu [Flags] ile ilişkilendirin, değerleri ikinin üslerine ayarlayın ve bu şekilde çalışacaktır.

Bir işleve birden çok değer iletmekten başka hiçbir şey değişmez.

Örneğin:

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

Daha fazla ayrıntı için, Numaralandırma Türleriyle ilgili MSDN belgelerine bakın .


Soruya yapılan eklemelere yanıt olarak düzenleyin.

Bir dizi / koleksiyon / parametreler dizisi olarak geçmek gibi bir şey yapmak istemediğiniz sürece, bu numaralandırmayı olduğu gibi kullanamazsınız. Bu, birden çok değeri iletmenize izin verir. Bayraklar sözdizimi, Enum'un bayraklar olarak belirtilmesini gerektirir (veya dili tasarlanmamış bir şekilde alçaltmak için).


9
Bunun çalışmasını istiyorsanız, değerlerin ikinin üsleri olarak tanımlanması gerektiğini düşünüyorum, her değer için tek bir bit. Bitsel VE işlemlerini kullanarak kontrol edebileceğiniz, parametredeki değerlerin bitsel VEYA'sını iletmenizdir. Değerleri örneğin 1,2,4,8 gibi tanımlamaya özen göstermezseniz sorun yaşarsınız.
Denis Troller

1
Sadece Flags özniteliğini ayarlamak otomatik olarak çalışmaz. Ben sadece denedim.
Richard Anthony Hein

1
Haklısın ve yanlış bilgileri kaldırdım. Reed'in kodu da düzeltildi.
Matthew Scharley

@monoxide: Aynı zamanda düzelttim - düzenlemelerinizi geçersiz kıldığım için üzgünüm.
Reed Copsey

2
Sorun değil ... Bunun gibi bayrak değerleri için hala onaltılık kullanmayı tercih ediyorum, bana daha açık görünüyor, ama her biri kendine göre.
Matthew Scharley

78

Bence daha zarif çözüm HasFlag () kullanmak:

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

Bu şekilde yaparsanız bilmeniz gereken önemli bir şey daha vardır: Numaranızı dinamik olarak doldurmanız gerektiğinde çok daha fazla esneklik sağlar. Örneğin: Programınızın çalışmasını istediğiniz günleri tanımlamak için onay kutularını kullanırsanız ve bunu yukarıdaki şekilde gerçekleştirmeye çalışırsanız, kod okunamayacaktır. Yani bunun yerine şu şekilde yapabilirsiniz: ... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN

25

Reed'in cevabını destekliyorum. Ancak, numaralandırmayı oluştururken, bir çeşit bit alanı oluşturması için her bir enum üyesinin değerlerini belirtmelisiniz. Örneğin:

[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
Haftanın Günleri değerini incelemeniz gerekirse, örneğin bir veritabanında saklanan bir değeri okuyorsanız size yardımcı olacaktır. Ayrıca, haftanın bazı günlerini Pazar yerine Pazartesinden başlayarak numaralandırdığından, diğer programcılara daha iyi belgeler sağlar.
Jacob

3
Netlik ve süreklilik için, "Tümü" numaranızı "Pazar | Pazartesi | Salı | Çarşamba | Perşembe | Cuma | Cumartesi" olarak yazarım ve "Hafta içi" ve "Hafta Sonu" için benzer bir gösterim kullanırdım.
Robert Cartaino

Kendi numaranızı oluşturmak istiyorsanız bu sorun değil, ancak soruyu yanıtlamak için mevcut DaysOfWeek numaralandırmasını değiştiremezsiniz
Robert Paulson

2
"İsteyebilir" değil ... GEREKİR. Bit tabanlı karşılaştırmalar bunu gerektirir. Değerleri belirtmeden bırakmak işe yaramayacaktır.
Richard Anthony Hein

11

Benim özel durumumda, System.DayOfWeek'i kullanmak istiyorum

System.DayOfWeek'i bir [Flags]numaralandırma olarak kullanamazsınız çünkü üzerinde kontrolünüz yoktur. Birden fazla kabul eden bir yönteme DayOfWeeksahip olmak istiyorsanız, paramsanahtar kelimeyi kullanmanız gerekecektir.

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

Aksi takdirde, [Flags]diğer yanıtlayıcılar tarafından belirtildiği gibi kendi numaralandırmanızı oluşturabilir ve bit tabanlı karşılaştırmalar kullanabilirsiniz.


2
Neden paramları düşünmediğimi bilmiyorum. Bu, bit alanı olmayan numaralandırmaları kullanmak için çok yararlı olacaktır.
Ronnie Overby

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

Sayıları belirtmeli ve bu şekilde artırmalısınız çünkü değerleri bit düzeyinde depoluyor.

Ardından bu numaralandırmayı almak için yönteminizi tanımlayın

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

ve buna benzer bir şey yapmak

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

Enum değerlerinden birinin dahil edilip edilmediğini kontrol etmek için bunları bitsel işlemler kullanarak kontrol edin.

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
  }
}

Soruyu cevaplamıyor. "Benim özel durumumda, System.DayOfWeek'i kullanmak isterim"
Robert Paulson

Ama tam olarak aradığım şey buydu. Yine de teşekkürler.
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
    }

yöntemi bu formatta çağırın

MethodName (HaftanınGünleri.Salı | Haftanın Günleri.Perşembe);

Geçilen seçenekleri almak için bir EnumToArray yöntemi uygulayın

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

Soruyu cevaplamıyor. "Benim özel durumumda, System.DayOfWeek'i kullanmak istiyorum"
Robert Paulson

Teşekkürler Robert, ama bunu her yanıtta belirtmek zorunda değilsin.
Ronnie Overby

@Ronnie - Aslında soruyu cevaplamayan pek çok neredeyse yinelenen cevap olması benim hatam değil.
Robert Paulson

@Rony - ToString () ve Enum.Parse () numaralandırmaları bir [Flags] numaralandırmasını doğru bir şekilde çıkaracak / ayrıştıracaktır (elbette numaralandırma sürümlemesine dikkat ettiğiniz sürece)
Robert Paulson

@Robert - Kimsenin seni suçladığını sanmıyorum. Bırakın oylar konuşsun.
Ronnie Overby

3

Numaranızı [İşaretler] özniteliğiyle işaretleyin. Ayrıca, sizin durumunuzda 1,2,4,8,16,32,64 gibi tüm değerlerinizin birbirini dışladığından (iki değer birbirine eşit olamaz) emin olun

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

Bir DayOfWeek numaralandırmasını kabul eden bir yönteminiz olduğunda, birden çok üyeyi birlikte kullanmak için bitsel veya işleci (|) kullanın. Örneğin:

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

Parametrenin belirli bir üye içerip içermediğini kontrol etmek için, aradığınız üye ile bitsel ve işleci (&) kullanın .

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

Soruyu cevaplamıyor. "Benim özel durumumda, System.DayOfWeek'i kullanmak isterim"
Robert Paulson

2

Reed Copsey haklı ve eğer yapabilseydim orijinal gönderiye eklerdim, ama yapamam, bu yüzden cevap vermek zorunda kalacağım.

Herhangi bir eski numaralandırmada yalnızca [Flags] kullanmak tehlikelidir. Değerlerdeki çatışmaları önlemek için bayrakları kullanırken enum değerlerini açıkça ikinin üslerine değiştirmeniz gerektiğine inanıyorum. FlagsAttribute ve Enum için yönergelere bakın .



-3

Bu nitelikteki bir şey, aradığınızı göstermelidir:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.