2012-01-31 20 views
7

Mam trudności z pracą z niektórymi wyliczeniami starszymi, które mają wiele wartości zerowych. Ilekroć wywołuję ToString na jednej z niezerowych wartości, uwzględniane są wszystkie oprócz pierwszej wartości zera.Uzyskiwanie nazw elementów z tabel wyliczeniowych z wieloma wartościami zerowymi

Czy istnieje sposób na wyodrębnienie niezerowej nazwy wartości bez odwoływania się do manipulacji ciągiem lub odbicia?

//all of the following output "Nada, Zilch, One" 
Console.WriteLine(TestEnum.One); 
Console.WriteLine(Convert.ToString(TestEnum.One)); 
Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum)) 
         .ConvertToString(TestEnum.One)); 

[Flags] 
enum TestEnum 
{ 
    Zero = 0, 
    Nada = 0, 
    Zilch = 0, 
    One = 1 
} 

Edit

Rozumiem, że posiadanie wielu elementów z tej samej wartości nie jest jednak enum w pytaniu jest zdefiniowana w zespole starszego typu, że nie mogę zmienić zalecane. W rzeczywistości istnieje 12 teksty stałe publiczne mscorlib v4, które rozkładają się do tego zalecenia, jak ustala się według następującego prostej kwerendy LINQ:

var types = typeof (void).Assembly.GetTypes() 
    .Where(type => type.IsEnum && 
        type.IsPublic && 
        Enum.GetValues(type).Cast<object>() 
         .GroupBy(value => value) 
         .Any(grp => grp.Count() > 1)) 
    .ToList(); 
+1

To powszechna praktyka, aby mieć tylko jedną wartość zerową. W rzeczywistości powszechną praktyką jest nie powtarzanie żadnych wartości. Jest to enum i nieodłączne niebezpieczeństwo polega na wartości "wsparcia". –

+0

Czy możesz pokazać kod, w jaki sposób używane są te flagi? Czy są używane jako maski bitowe? – Maggie

+0

Ponieważ jest to oczywiście niepożądane zachowanie, możesz złożyć raport o błędzie: http://connect.microsoft.com. – Heinzi

Odpowiedz

1

Oto jeden opcja. Działa, ale jest trochę brzydki. Zmienne wartości/nazwy nie ulegną zmianie, więc wystarczy je wyliczyć tylko jeden raz.

Zakładając, że nieco bardziej skomplikowane wyliczenia, takie jak:

[Flags] 
public enum TestEnum 
{ 
    Zero = 0, 
    Nada = 0, 
    Zilch = 0, 
    One = 1, 
    Two = 2, 
    Three = 3, 
    Four = 4 
} 

Oto kod można użyć:

var input = TestEnum.One | TestEnum.Two; 
var values = (TestEnum[]) Enum.GetValues(typeof (TestEnum)); 
var names = Enum.GetNames(typeof (TestEnum)); 
var result = values 
    .Select((value, index) => 
      input == value || (value != 0 && (input & value) == value) 
       ? names[index] 
       : null) 
    .Where(name => name != null); 
var text = string.Join(", ", result); 
Console.WriteLine(text); 
+0

Zrobiłem twój kod LINQ bardziej idiomatyczny, mam nadzieję, że nie masz nic przeciwko. Podoba mi się to rozwiązanie, ale nie działa dla wartości 0. –

+0

Zaktualizowano - teraz działa dla 0 wartości. – CodeThug

1

Alright, pierwsze Microsoft recommends against this strongly. Niektóre z silniejszych słów, które słyszałem, używają do czegoś, czego nie wymuszają podczas kompilacji:

Unikaj ustawiania wartości wyliczania flag na zero, chyba że ta wartość jest używana do wskazania, że ​​wszystkie flagi zostały wyczyszczone. Taką wartość należy nazwać odpowiednio zgodnie z opisem w następnej wytycznej ... Podaj zerową wartość wyliczeń flag Brak. W przypadku wyliczenia flag wartość musi zawsze oznaczać, że wszystkie flagi zostały wyczyszczone.

OK, więc dlaczego tak się dzieje? Od this question biorę to Enum.ToString zachowuje się dziwnie:

Jeśli wielu użytkowników wyliczenie mają taką samą wartość podstawową i próbować odzyskać znaków reprezentujący nazwę członek wyliczenie oparte na wartości bazowej, Twój kod nie powinien dokonywać żadnych założeń o której nazwie metoda zwróci.

EDYCJA: Jestem w stanie odtworzyć wyniki, ale nie mogę znaleźć więcej dokumentacji na temat, dlaczego zacząłby drukować inne wartości 0. Spodziewałbym się, że nie wydrukuje żadnego z nich.

Czy wystarczy kliknąć prawym przyciskiem myszy-> refaktor-> zmienić nazwy wszystkich tak samo, a następnie usunąć pozostałe? Wydaje się łatwiej i mniej wbrew temu, co zaleca Microsoft.

+0

To jest starsza wersja zdefiniowana w zespole, którego nie można zmienić. –

+0

Dlaczego jesteś przeciwny refleksji? Jakiś konkretny powód? Z pewnością jest to możliwe. – DanTheMan

+0

Nie jestem całkowicie przeciwko temu, ale wolałbym, żeby był używany tylko w ostateczności. Dodatkowo mój kod może wymagać uruchomienia w częściowym środowisku zaufania. –

0
Enum.GetValues(typeof (TestEnum)) 

powraca

{ClassLibrary5.Class1.TestEnum[4]} 
[0] Zilch ClassLibrary5.Class1.TestEnum 
[1] Zilch ClassLibrary5.Class1.TestEnum 
[2] Zilch ClassLibrary5.Class1.TestEnum 
[3] One ClassLibrary5.Class1.TestEnum 

miałem zamiar zacytować ten sam fragment Dan zrobił. Do czego te mają być używane? Co musisz zrobić z tymi wyliczeniami?

0

Zakładając, że mają nieco bardziej skomplikowanego wyliczenia, takie jak:

[Flags] 
public enum TestEnum 
{ 
    Zero = 0, 
    Nada = 0, 
    Zilch = 0, 
    One = 1, 
    Two = 2, 
    Four = 4, 
}

Można zaimplementować prostą metodę, która zwraca ciąg znaków dla ciebie coś takiego:

public static string TestEnumToString(TestEnum value) 
{ 
    var result = new List(); 

    if (value == TestEnum.Zero) 
    { 
     result.Add("Zero"); 
    } 
    if (value == TestEnum.Nada) 
    { 
     result.Add("Nada"); 
    } 
    if (value == TestEnum.Zilch) 
    { 
     result.Add("Zilch"); 
    } 
    if ((value & TestEnum.One) != 0) 
    { 
     result.Add("One"); 
    } 
    if ((value & TestEnum.Two) != 0) 
    { 
     result.Add("Two"); 
    } 
    if ((value & TestEnum.Four) != 0) 
    { 
     result.Add("Four"); 
    } 

    return string.Join(",", result); 
}
+1

Ten przykład nie będzie działał poprawnie, ponieważ jest oznaczony jako "flagi". Jeśli mam 0x03 jako moją wartość, ale tylko 0x01 i 0x02 w moim wyliczeniu, to wyrzucę wyjątek AgumentException. – DanTheMan

+0

Zaktualizowany kod do uwzględnienia atrybutu Flagi. Zapoznaj się. – CodeThug

+0

To rozwiązanie powoduje obciążenie dla przyszłych programistów. Wolę twoją drugą sugestię. –

Powiązane problemy