如何在C#中添加有关枚举类型的每个枚举值的元数据信息?

问题描述 投票:1回答:7

我想列出带有扩展数据的枚举值。数据库将只保存一个与我的枚举值相对应的整数值,但是在代码中,我希望获得的信息不仅仅是枚举名称。

让我举个例子:

public enum Reason
{
    NotEnoughStock, // Valid = yes, Responsability = company, Text = There is not enough stock
    ProductNotAvailabe, // Valid = no, Responsability = company, Text = Produc is not available
    PaymentNotDone, // Valid = no, Responsability = client, Text = Payment is not done
    BlackListedClient, // Valid = no, Responsability = client, Text = Client is black listed
    NotEnoughTime // Valid = yes, Responsability = company, Text = There is not enough time
}

我该怎么做?除了枚举,我还应该使用其他东西吗?我喜欢枚举。

c# enums metadata
7个回答
2
投票

您可以:

  • 使用Attributes (C#);或
  • 创建通过诸如Helper.GetExtraInfo(MyType val)之类的方法返回额外信息的帮助器类。

对于'Text'值,您可以使用DescriptionAttribute。对于其他两个,我认为您应该创建新属性。

class ValidAttribute : Attribute
{
    public bool Valid { get; private set; }

    public ValidAttribute(bool valid)
    {
        this.valid = valid;
    }
}

Get enum from enum attribute包含用于读取属性值的扩展方法。


1
投票

您可以为枚举创建扩展方法,以便仍然可以享受枚举并在Reason对象中获取数据。

var reason = Reason.NotEnoughStock.GetReasonInfo(ReasonData);

样本

internal class Program
{
    public static void Main(string[] args)
    {
        var reason = ReasonConstant.Reason.NotEnoughStock.GetReasonInfo(ReasonData);
    }
}

public static class ReasonUtils
{
    public static ReasonInfo GetReasonInfo(this ReasonConstant.Reason reason, Dictionary<ReasonConstant.Reason, ReasonInfo> reasonData)
    {
        if (reasonData == null)
            return null;
        if (!reasonData.ContainsKey(reason))
            return null;
        else
            return reasonData[reason];
    }
}

public class ReasonInfo
{
    public bool IsValid { get; set; }
    public string Responsability { get; set; }
    public string Text { get; set; }
}

public static class ReasonConstant
{
    public enum Reason
    {
        NotEnoughStock, // Valid = yes, Responsability = company, Text = There is not enough stock
        ProductNotAvailabe, // Valid = no, Responsability = company, Text = Produc is not available
        PaymentNotDone, // Valid = no, Responsability = client, Text = Payment is not done
        BlackListedClient, // Valid = no, Responsability = client, Text = Client is black listed
        NotEnoughTime // Valid = yes, Responsability = company, Text = There is not enough time
    }
}

1
投票

在tymtam和Kevin的共同帮助下,我做到了:

void Main()
{
    Reason.NotEnoughStock.GetAttributeOfType<DescriptionAttribute>().Description;
    Reason.ProductNotAvailabe.GetAttributeOfType<ResponsabilityAttribute>().Responsability;
}

public enum Reason
{
    [Description("There is not enough stock")]
    [Valid(true)]
    [Responsability("company")]
    NotEnoughStock, 

    [Description("Produc is not available")]
    [Valid(false)]
    [Responsability("company")]
    ProductNotAvailabe,

    [Description("Payment is not done")]
    [Valid(false)]
    [Responsability("client")]
    PaymentNotDone, 

    [Description("Client is black listed")]
    [Valid(false)]
    [Responsability("client")]
    BlackListedClient, 

    [Description("There is not enough time")]
    [Valid(true)]
    [Responsability("company")]
    NotEnoughTime 
}

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (attributes.Length > 0) ? (T)attributes[0] : null;
    }
}

public class ValidAttribute : Attribute
{
    public bool Valid;
    public ValidAttribute(bool valid) { Valid = valid; }
}

public class ResponsabilityAttribute : Attribute
{
    public string Responsability;
    public ResponsabilityAttribute(string responsability) { Responsability = responsability; }
}

0
投票

没有简单的方法可以实现您的目标。

您必须手动执行所需的行为。

您可能会考虑创建一个类,使其具有良好而适当的设计,并能够简单高效地使用它,因为实际上您询问如何创建以枚举值作为键的实例的字典。

因此拥有:

Reason.cs

public enum Reason
{
  NotEnoughStock,
  ProductNotAvailabe,
  PaymentNotDone,
  BlackListedClient,
  NotEnoughTime
}

您可以创建此枚举:

Responsability.cs

public enum Responsability
{
  None,
  Company,
  Client
}

并且该类允许在实例中存储枚举的元数据,并提供在静态构造函数中初始化的所有枚举类型的元数据的静态列表:

ReasonMetaData.cs

using System.Collections.Generic;

public class ReasonMetaData
{

  static public Dictionary<Reason, ReasonMetaData> All { get; private set; }
  static ReasonMetaData()
  {
    All = new Dictionary<Reason, ReasonMetaData>();
    All.Add(
      Reason.NotEnoughStock,
      new ReasonMetaData(Responsability.Company, "There is not enough stock", true));
    All.Add(
      Reason.ProductNotAvailabe,
      new ReasonMetaData(Responsability.Company, "Product is not available", false));
    All.Add(
      Reason.PaymentNotDone,
      new ReasonMetaData(Responsability.Client, "Payment is not done", false));
    All.Add(
      Reason.BlackListedClient,
      new ReasonMetaData(Responsability.Client, "Client is black listed", false));
    All.Add(
      Reason.NotEnoughTime,
      new ReasonMetaData(Responsability.Company, "There is not enough time", true));
  }
  static public ReasonMetaData Get(Reason index)
  {
    return All[index];
  }
  public Responsability Responsability { get; private set; }
  public string Text { get; private set; }
  public bool Valid { get; private set; }

  public override string ToString()
  {
    return $"Responsability = {Enum.GetName(typeof(Responsability), Responsability)}, " +
           $"Text = {Text}, " +
           $"Valid = {( Valid ? "yes" : "no" )}";
  }

  private ReasonMetaData()
  {
  }

  private ReasonMetaData(Responsability responsability, string text, bool valid)
  {
    Responsability = responsability;
    Text = text;
    Valid = valid;
  }
}

您还可以按照@RawitasKrungkaew的建议创建扩展方法:

ReasonMetadataHelper.cs

static public class ReasonMetadataHelper
{
  static public ReasonMetaData GetMetaData(this Reason reason)
  {
    return ReasonMetaData.Get(reason);
  }
}

使用和测试

static void Test()
{
  Console.WriteLine("Metadata of Reason.NotEnoughStock is:");
  Console.WriteLine(Reason.NotEnoughStock.GetMetaData());
  Console.WriteLine("");
  Console.WriteLine("Metadata of Reason.ProductNotAvailabe is:");
  Console.WriteLine(ReasonMetaData.Get(Reason.ProductNotAvailabe));
  Console.WriteLine("");
  Console.WriteLine("All metadata of Reason enum are:");
  foreach ( var item in ReasonMetaData.All )
    Console.WriteLine($"  {item.Key}: {item.Value}");
}

输出

Metadata of Reason.NotEnoughStock is:
Responsability = Company, Text = There is not enough stock, Valid = yes

Metadata of Reason.ProductNotAvailabe is:
Responsability = Company, Text = Product is not available, Valid = no

All metadata of Reason enum are:
  NotEnoughStock: Responsability = Company, Text = There is not enough stock, Valid = yes
  ProductNotAvailabe: Responsability = Company, Text = Product is not available, Valid = no
  PaymentNotDone: Responsability = Client, Text = Payment is not done, Valid = no
  BlackListedClient: Responsability = Client, Text = Client is black listed, Valid = no
  NotEnoughTime: Responsability = Company, Text = There is not enough time, Valid = yes

改进

您可以将此解决方案与属性混合以通过解析枚举项的属性来自动创建列表:

因此拥有:

ReasonAttributes.cs

public class ReasonResponsabilityAttribute : Attribute
{
  public Responsability Responsability { get; private set; }
  public ReasonResponsabilityAttribute(Responsability responsability)
  {
    Responsability = responsability;
  }
}

public class ReasonTextAttribute : Attribute
{
  public string Text { get; private set; }
  public ReasonTextAttribute(string text)
  {
    Text = text;
  }
}

public class ReasonValidAttribute : Attribute
{
  public bool Valid { get; private set; }
  public ReasonValidAttribute(bool valid)
  {
    Valid = valid;
  }
}

Reason.cs现在是:

public enum Reason
{

  [ReasonResponsability(Responsability.Company)]
  [ReasonText("There is not enough stock")]
  [ReasonValid(true)]
  NotEnoughStock,

  // ...
  ProductNotAvailabe,

  // ...
  PaymentNotDone,

  // ...
  BlackListedClient,

  // ...
  NotEnoughTime

}

ReasonMetadata.cs静态构造函数现在是:

using System.Reflection;

static ReasonMetaData()
{
  All = new Dictionary<Reason, ReasonMetaData>();
  var list = Enum.GetValues(typeof(Reason));
  foreach ( Reason reason in list )
  {
    var metadata = new ReasonMetaData();
    var memberinfo = reason.GetType().GetMember(Enum.GetName(typeof(Reason), reason));
    if ( memberinfo.Length == 1 )
    {
      var attributes = memberinfo[0].GetCustomAttributes();
      foreach ( Attribute attribute in attributes )
        if ( attribute is ReasonResponsabilityAttribute )
          metadata.Responsability = ( (ReasonResponsabilityAttribute)attribute ).Responsability;
        else
        if ( attribute is ReasonTextAttribute )
          metadata.Text = ( (ReasonTextAttribute)attribute ).Text;
        else
        if ( attribute is ReasonValidAttribute )
          metadata.Valid = ( (ReasonValidAttribute)attribute ).Valid;
    }
    All.Add(reason, metadata);
  }
}

仅使用一个属性

ReasonMetadataAttribute.cs

public class ReasonMetadataAttribute : Attribute
{
  public Responsability Responsability { get; private set; }
  public string Text { get; private set; }
  public bool Valid { get; private set; }
  public ReasonMetadataAttribute(Responsability responsability, string text, bool valid)
  {
    Responsability = responsability;
    Text = text;
    Valid = valid;
  }
}

ReasonMetadata.cs静态构造函数现在是:

static ReasonMetaData()
{
  All = new Dictionary<Reason, ReasonMetaData>();
  var list = Enum.GetValues(typeof(Reason));
  foreach ( Reason reason in list )
  {
    var metadata = new ReasonMetaData();
    var memberinfo = reason.GetType().GetMember(Enum.GetName(typeof(Reason), reason));
    if ( memberinfo.Length == 1 )
    {
      var attributes = memberinfo[0].GetCustomAttributes();
      foreach ( Attribute attribute in attributes )
        if ( attribute is ReasonMetadataAttribute )
        {
          var metadataAttribute = (ReasonMetadataAttribute)attribute;
          metadata.Responsability = metadataAttribute.Responsability;
          metadata.Text = metadataAttribute.Text;
          metadata.Valid = metadataAttribute.Valid;
        }
    }
    All.Add(reason, metadata);
  }
}

用法:

public enum Reason
{
  [ReasonMetadata(Responsability.Company, "There is not enough stock", true)]
  NotEnoughStock,
  // ...
  ProductNotAvailabe,
  // ...
  PaymentNotDone,
  // ...
  BlackListedClient,
  // ...
  NotEnoughTime
}

-1
投票

[创建一个类来存储其他信息,例如ReasonDetail,然后使用Dictionary<Reason, ReasonDetail>并提供ReasonReasonDetail之间的映射


-1
投票

这里有很多很好的答案,但是我觉得您要的是/// <summary> XML文档。

    public enum Reason
    {
        /// <summary>
        ///  Valid = yes, Responsability = company, Text = There is not enough stock
        /// </summary>
        NotEnoughStock,
        /// <summary>
        /// Valid = no, Responsability = company, Text = Produc is not available
        /// </summary>
        ProductNotAvailabe,
        /// <summary>
        /// Valid = no, Responsability = client, Text = Payment is not done
        /// </summary>
        PaymentNotDone,
        /// <summary>
        /// Valid = no, Responsability = client, Text = Client is black listed
        /// </summary>
        BlackListedClient,
        /// <summary>
        /// Valid = yes, Responsability = company, Text = There is not enough time
        /// </summary>
        NotEnoughTime 
    }

Hover XML Documented Type Example Screenshot

请参阅XML Documentation Comments以获取更多信息。


此外,您可以选择在构建时生成XML文档(请参考在代码库中定义它们的类型)

Build XML Document Generation Checkbox Screenshot

注意:如果您使用git版本控制,请将此生成的文件添加到.gitignore。


-1
投票

您的样本看起来可能是:

public enum Reason
{
    None = 0,
    Valid = 1,
    CompanyResponsible = 2,
    ClientResponsible = 4, 

    // Valid = yes, Responsability = company, Text = There is not enough stock
    [Description("There is not enough stock")
    NotEnoughStock = Valid | CompanyResponsible | 8, 
    ...

    // Valid = yes, Responsability = company, Text = There is not enough time
    [Description("There is not enough time")
    NotEnoughTime = Valid | CompanyResponsible | 128,          
}

也许您可以排除一些单独的概念来替换| 8部分。

© www.soinside.com 2019 - 2024. All rights reserved.