jak sprawdzić, czy wartość ciągu znajduje się na liście wyliczeń?

92

W moim ciągu zapytania mam zmienną wieku ?age=New_Born.

Czy istnieje sposób, aby sprawdzić, czy ta wartość ciągu New_Bornznajduje się na mojej liście Enum

[Flags]
public enum Age
{
    New_Born = 1,
    Toddler = 2,
    Preschool = 4,
    Kindergarten = 8
}

Mógłbym teraz użyć instrukcji if, ale jeśli moja lista Enum się powiększy. Chcę znaleźć lepszy sposób, aby to zrobić. Zastanawiam się nad użyciem Linq, tylko nie wiem, jak to zrobić.

qinking126
źródło
3
Enum.IsDefinednie w porządku?
leppie

Odpowiedzi:

155

Możesz użyć:

 Enum.IsDefined(typeof(Age), youragevariable)
AaronS
źródło
IsDefined wymaga do sprawdzenia instancji Enum
Viacheslav Smityukh
9
Pamiętaj, że Enum.IsDefined()rozróżniana jest wielkość liter! Nie jest to więc „uniwersalne rozwiązanie”.
Cheshire Cat
7
Zwykle nie zaleca się używania funkcji IsDefined, ponieważ używa ona odbicia, przez co wywołanie IsDefined jest bardzo kosztowne pod względem wydajności i procesora. Zamiast tego użyj TryParse. (informacje z pluralsight.com)
Weihui Guo
41

Możesz użyć metody Enum.TryParse:

Age age;
if (Enum.TryParse<Age>("New_Born", out age))
{
    // You now have the value in age 
}
John Koerner
źródło
5
To jest dostępne tylko od .NET 4
Gary Richter,
2
Problem z tym polega na tym, że zwróci wartość true, jeśli podasz JAKĄKOLWIEK liczbę całkowitą (zamiast ciągu „New_Born”, mam na myśli).
Romain Vincent
11

Możesz użyć metody TryParse , która zwraca wartość true, jeśli się powiedzie:

Age age;

if(Enum.TryParse<Age>("myString", out age))
{
   //Here you can use age
}
Omar
źródło
2

Mam poręczną metodę rozszerzającą, która używa TryParse, ponieważ IsDefined rozróżnia wielkość liter.

public static bool IsParsable<T>(this string value) where T : struct
{
    return Enum.TryParse<T>(value, true, out _);
}
Andy
źródło
1

Aby osiągnąć swój cel, powinieneś użyć Enum.TryParse

Oto przykład:

[Flags]
private enum TestEnum
{
    Value1 = 1,
    Value2 = 2
}

static void Main(string[] args)
{
    var enumName = "Value1";
    TestEnum enumValue;

    if (!TestEnum.TryParse(enumName, out enumValue))
    {
        throw new Exception("Wrong enum value");
    }

    // enumValue contains parsed value
}
Viacheslav Smityukh
źródło
1

Wiem, że jest to stary wątek, ale tutaj jest nieco inne podejście wykorzystujące atrybuty w wyliczeniach, a następnie klasa pomocnicza, aby znaleźć wyliczenie, które pasuje.

W ten sposób można mieć wiele mapowań na jednym wyliczeniu.

public enum Age
{
    [Metadata("Value", "New_Born")]
    [Metadata("Value", "NewBorn")]
    New_Born = 1,
    [Metadata("Value", "Toddler")]
    Toddler = 2,
    [Metadata("Value", "Preschool")]
    Preschool = 4,
    [Metadata("Value", "Kindergarten")]
    Kindergarten = 8
}

Z taką klasą pomocników

public static class MetadataHelper
{
    public static string GetFirstValueFromMetaDataAttribute<T>(this T value, string metaDataDescription)
    {
        return GetValueFromMetaDataAttribute(value, metaDataDescription).FirstOrDefault();
    }

    private static IEnumerable<string> GetValueFromMetaDataAttribute<T>(T value, string metaDataDescription)
    {
        var attribs =
            value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof (MetadataAttribute), true);
        return attribs.Any()
            ? (from p in (MetadataAttribute[]) attribs
                where p.Description.ToLower() == metaDataDescription.ToLower()
                select p.MetaData).ToList()
            : new List<string>();
    }

    public static List<T> GetEnumeratesByMetaData<T>(string metadataDescription, string value)
    {
        return
            typeof (T).GetEnumValues().Cast<T>().Where(
                enumerate =>
                    GetValueFromMetaDataAttribute(enumerate, metadataDescription).Any(
                        p => p.ToLower() == value.ToLower())).ToList();
    }

    public static List<T> GetNotEnumeratesByMetaData<T>(string metadataDescription, string value)
    {
        return
            typeof (T).GetEnumValues().Cast<T>().Where(
                enumerate =>
                    GetValueFromMetaDataAttribute(enumerate, metadataDescription).All(
                        p => p.ToLower() != value.ToLower())).ToList();
    }

}

możesz wtedy zrobić coś takiego

var enumerates = MetadataHelper.GetEnumeratesByMetaData<Age>("Value", "New_Born");

A dla kompletności jest tutaj atrybut:

 [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = true)]
public class MetadataAttribute : Attribute
{
    public MetadataAttribute(string description, string metaData = "")
    {
        Description = description;
        MetaData = metaData;
    }

    public string Description { get; set; }
    public string MetaData { get; set; }
}
jwsadler
źródło
0

Aby przeanalizować wiek:

Age age;
if (Enum.TryParse(typeof(Age), "New_Born", out age))
  MessageBox.Show("Defined");  // Defined for "New_Born, 1, 4 , 8, 12"

Aby sprawdzić, czy jest zdefiniowane:

if (Enum.IsDefined(typeof(Age), "New_Born"))
   MessageBox.Show("Defined");

W zależności od tego, jak planujesz używać Agewyliczenia, flagi mogą nie być właściwe. Jak zapewne wiesz, [Flags]oznacza, że ​​chcesz zezwolić na wiele wartości (jak w masce bitowej). IsDefinedzwróci false, Age.Toddler | Age.Preschoolponieważ ma wiele wartości.

agent-j
źródło
2
Powinien używać TryParse, ponieważ jest to niezweryfikowane dane wejściowe.
Servy
1
MessageBox nie ma sensu w środowisku sieciowym.
Servy