a

Câu hỏi Enums với giá trị chuỗi và tìm enum theo giá trị


Tôi muốn có một enum như sau và sau đó có một phương pháp một cái gì đó như Util.FindFruitByValue ("A") mà trả về enum Apple. điều này là do các từ viết tắt được lưu trữ trong cơ sở dữ liệu và tôi cần phải chuyển đổi chúng thành các enums thích hợp sau khi đọc từ db. là điều này có thể HOẶC tôi có cần tạo một lớp riêng cho nó không? Làm ơn cho tôi biết. cảm ơn trước.

public enum Fruit
{
    Apple = "A"
    Banana = "B"
    Cherry = "C"
}

Cập nhật: điều này giống như một bảng tra cứu, nhưng sự khác biệt là giá trị là chuỗi thay vì một int. Tôi đang điền một đối tượng nghiệp vụ, bằng cách đọc các giá trị từ cơ sở dữ liệu và tôi muốn sử dụng một kiểu có các giá trị cố định cho thuộc tính đối tượng thay vì chuỗi.


7
2017-08-17 11:38


gốc


Bạn sẽ sử dụng Enum để làm gì? Tại sao bạn không thể sử dụng "A", "B", "C" cho tên của các giá trị Enum của bạn? Hoặc bạn có thể chuyển tên đầy đủ các giá trị của mình thay vì viết tắt không? - Benjol
Tôi có một đối tượng kinh doanh và một số thuộc tính của nó tương ứng với các giá trị viết tắt cố định trong cơ sở dữ liệu. do đó, để làm cho thuộc tính được gõ mạnh mẽ (và hiển thị toàn văn cho chữ viết tắt trên màn hình), tôi đã nghĩ đến việc sử dụng enum thay vì tạo một lớp riêng biệt cho nó, nhưng tiếc là enums chỉ có thể có giá trị số nguyên. đó là lý do tại sao câu hỏi. - RKP


Các câu trả lời:


Tôi đã giải quyết vấn đề bằng cách sử dụng thuộc tính Description trên enum. giải pháp như sau. Tôi sử dụng phương pháp mở rộng để có được mô tả. mã để lấy mô tả được lấy từ liên kết này http://blog.spontaneouspublicity.com/post/2008/01/17/Associating-Strings-with-enums-in-C.aspx. cảm ơn câu trả lời của bạn.

    public enum Fruit
{
    [Description("Apple")]
    A,
    [Description("Banana")]
    B,
    [Description("Cherry")]
    C
}

public static class Util
{
    public static T StringToEnum<T>(string name)
    {
        return (T)Enum.Parse(typeof(T), name);
    }

    public static string ToDescriptionString(this Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());

        DescriptionAttribute[] attributes =
            (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute),
            false);

        if (attributes != null &&
            attributes.Length > 0)
            return attributes[0].Description;
        else
            return value.ToString();
    }
}

19
2017-08-17 13:32



Nothin 'giống như một chút Reflection ... - RobS
thực sự phản ánh chậm nói chung, nhưng tôi không thể tìm ra cách nào khác để giải quyết vấn đề này. Tôi cần loại có giá trị cố định và thay vì tạo lớp tùy chỉnh cho các loại thông tin khác nhau, enum thuận tiện để sử dụng, nhưng thiếu hỗ trợ cho giá trị chuỗi, đó là lý do tôi phải chọn tùy chọn này. Tôi sẽ hoan nghênh bất kỳ đề xuất để thực hiện điều này một cách tốt hơn. - RKP


Bạn có thể đặt các giá trị trong một Dictionary để xem xét hiệu quả chúng:

Dictionary<string, Fruit> fruitValues = new Dictionary<string, Fruit>();
fruitValues.Add("A", Fruit.Apple);
fruitValues.Add("B", Fruit.Banana);
fruitValues.Add("C", Fruit.Cherry);

Tra cứu:

string dataName = "A";
Fruit f = fruitValues[dataName];

Nếu giá trị có thể không tồn tại:

string dataName = "A";
Fruit f;
if (fruitValues.TryGetValue(dataName, out f)) {
  // got the value
} else {
  // there is no value for that string
}

11
2017-08-17 11:55





Tôi đã viết một thư viện xử lý chính xác vấn đề này. Nó ban đầu được dự định chỉ để làm ngược lại (trả về một giá trị chuỗi từ và Enum) nhưng một khi tôi đã viết rằng, có thể phân tích một chuỗi trở lại Enum của nó, chỉ là một bước ngắn.

Thư viện được gọi là EnumStringValues ​​và có sẵn từ nuget trong VS (trang gói cũng ở đây: https://www.nuget.org/packages/EnumStringValues) SourceCode có trên GitHub tại đây: https://github.com/Brondahl/EnumStringValues

Suy nghĩ và bình luận được hoan nghênh. Cảm hứng rõ ràng đến từ cách tiếp cận thuộc tính được công bố công khai được tham chiếu trong các câu trả lời khác ở đây.


2
2017-07-13 10:28





Làm thế nào về việc sử dụng Hashtable?


1
2017-08-17 11:42



+1 nhưng từ điển tốt hơn - Mina Gabriel


Xin lỗi, tôi đã bỏ qua định nghĩa của Enum của OP. Rõ ràng, các giá trị Enum phải là một kiểu số, do đó định nghĩa của OP sẽ không hoạt động.

Một ý nghĩ tôi có là sử dụng giá trị char làm giá trị Enum, ví dụ:

public enum Fruit
{
    Apple  = 65, //"A",
    Banana = 66, // "B",
    Cherry = 67 //"C"
}

Theo Convert.ToInt32 ('A') - không chắc chắn phải làm gì với độ nhạy trường hợp ở đây. Sau đó, lấy kết quả chính xác bằng cách truyền. Tôi vẫn đang chơi đùa với một ví dụ, rất vui khi nghe một số gợi ý.

OK, xin lỗi vì sự chậm trễ. Dưới đây là một chút về điều này:

public static class EnumConverter<T>
{
    public static T ToEnum(char charToConvert, out bool success)
    {
        try
        {                
            int intValue = Convert.ToInt32(charToConvert);                
            if (Enum.IsDefined(typeof(T), intValue))
            {
                success = true;
                return (T)Enum.ToObject(typeof(T), intValue);
            }
       }
       catch (ArgumentException ex)
       {
               // Use your own Exception Management Here
       }
       catch (InvalidCastException ex)
       {
           // Use your own Exception Management Here
       }
       success = false;
       return default(T);
    }
}

Sử dụng:

bool success = false;
Fruit selected = EnumConverter<Fruit>.ToEnum('A', out success);
if (success)
{
   // go for broke
}

1
2017-08-17 11:42



Anh ấy muốn đưa vào "A" và ra ngoài Fruit.Apple, đó có phải là mã của bạn không? - Benjol
@ Benjol: Vâng, đó là những gì nó làm. Nó cũng sẽ trả về Fruit.Apple cho chuỗi "Apple". - Lazarus
Bạn có thể chỉ ra cách Fruit enum nên được xác định để thực hiện công việc này? - Ben Voigt
Rõ ràng bạn không thể có một Enum với các giá trị chuỗi, những gì bạn có thể làm là chuyển đổi 'A', 'B' thành Int và sau đó thực hiện một phép diễn. Ví dụ. Apple = 65 - RobS


Tôi đã tạo ra một lớp DynamicEnum nhỏ giúp dễ dàng kéo các enums vào và ra khỏi cả kho lưu trữ miền và dữ liệu.

public abstract class DynamicEnum<T> : IEquatable<T>, IComparable<T>
    where T : DynamicEnum<T>, new()
{
    #region Instance

    public int PathCode { get; private set; }
    public string PathValue { get; private set; }

    protected DynamicEnum() { }

    protected DynamicEnum(int pathCode, string pathValue)
    {
        PathCode = pathCode;
        PathValue = PathValue;
    }

    #region IEquatable<AreaStatus> Members

    public bool Equals(T other)
    {
        return PathCode == other.PathCode;
    }

    #endregion

    public override bool Equals(object obj)
    {
        return Equals(obj as T);
    }

    public override int GetHashCode()
    {
        return PathCode.GetHashCode();
    }

    #region IComparable<AreaStatus> Members

    public int CompareTo(T other)
    {
        return PathCode.CompareTo(other.PathCode);
    }

    #endregion

    #endregion

    #region Class / Static

    static DynamicEnum()
    {
        // Despite appearances, static methods are not really inherited by
        // child classes. This means when the mapping fields below are accessed
        // by an implementing class the CLR does not see it as a method on that
        // class. In the event that the implementing class's static constructor
        // hasn't been called yet, it will not be called at that point since
        // technically no static method/property or instance of the implementing
        // class has been used. Working around this by creating an instance here
        // which causes the derived class's static constructor to be called
        // beforehand. This could alternately be solved by moving the default 'enum'
        // value initialization out of the implementing classes to the Global.asax 
        // where the database 'enum' values are optionally loaded.
        new T();
    }

    public static void Initialize(IEnumerable<T> statuses)
    {
        IntoDomainMapping = statuses.ToDictionary(x => x.PathValue, x => x);
        IntoDBMapping = IntoDomainMapping.ToDictionary(x => x.Value, x => x.Key);
    }

    public static Dictionary<string, T> IntoDomainMapping { get; protected set; }
    public static Dictionary<T, string> IntoDBMapping { get; protected set; }

    #endregion

    #region Operator Overloads

    public static bool operator ==(DynamicEnum<T> s1, T s2)
    {
        return s1.Equals(s2);
    }

    public static bool operator !=(DynamicEnum<T> s1, T s2)
    {
        return !s1.Equals(s2);
    }

    public static bool operator >(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) > 0;
    }

    public static bool operator <(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) < 0;
    }

    public static bool operator >=(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) >= 0;
    }

    public static bool operator <=(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) <= 0;
    }

    #endregion
}

Đây là lớp "Enum"

    public class ResourcePath : DynamicEnum<ResourcePath>
{
    public ResourcePath() { }

    public ResourcePath(int pathCode, string pathValue) 
        : base(pathCode, pathValue) { }


    static ResourcePath()
    {
        Initialize(new List<ResourcePath>
            {
                new ResourcePath(1, "customer.list"),
                new ResourcePath(1, "customer.create"),
                new ResourcePath(1, "customer.info"),
                new ResourcePath(1, "customer.update"),
                new ResourcePath(1, "customer.delete"),
            });
    }

    public static ResourcePath Deleted
    { 
        get { return ResourcePath.IntoDomainMapping["DE"]};
    }
}

Cuối cùng sử dụng cơ bản

var resource = GetAllResources().Where(e => e.PathCode == pathCode).firstOrDefault();

0
2017-11-12 16:51





Tôi biết đó là một bài cũ nhưng tôi đã có một vấn đề tương tự và tôi thấy ngày hôm qua một giải pháp cho nó.

Bạn có thể sử dụng kiểu enum an toàn kiểu như trong bài viết này được mô tả:

https://stackoverflow.com/a/424414/1257584


0
2018-01-15 16:24