【问题标题】:Enum as an parameter on it's own custom attribute constructor枚举作为它自己的自定义属性构造函数的参数
【发布时间】:2013-01-29 20:09:12
【问题描述】:

在这里我花了一些时间来了解更多关于 C# 的信息,所以我决定研究自定义属性,我发现它们在分配给 Enums 时非常有用。

所以我为 Enum 编写了一些扩展方法来很容易地检索这些属性,例如:DemoEnum.Value1.GetAttribute<EnumNote>()

过了一会儿,我想如果每个自定义属性都有一个对其分配的 Enum 的引用,那将是一个好主意。我认为这不是一个坏主意,所以我继续这样做:

首先我为自定义属性写了一个基类EnumAttribute,它当然继承了System.Attribute类。这个基类只是第一个草图,我打算扩展它以特别适合它将接收的每种 Enum 类型,但到目前为止这已经足够了。

public class EnumAttribute : Attribute
{
    public EnumInfo Enum { get; internal set; }

    public EnumAttribute(Enum Enum)
    {
        this.Enum = new EnumInfo(Enum);
    }

    public class EnumInfo
    {
        private Enum _value;
        private Type _type;
        private FieldInfo _details;

        public Enum Value { get { return _value; } }
        public Type Type { get { return _type; } }
        public FieldInfo Details { get { return _details; } }

        public EnumInfo(Enum value)
        {
        _value = value;
        _type = value.GetType();
        _details = _type.GetField(System.Enum.GetName(_type, value));
        }
    }
}

现在每个自定义属性都必须继承自此类 EnumAttribute。导致例如像EnumNote这样的类:

public class EnumNote : EnumAttribute
{
    private string _note = string.Empty;

    public string Note { get { return _note; } }

    public EnumNote(Enum Enum, string Note)
        : base(Enum)
    {
        _note = Note;
    }
}

到目前为止一切都很好,Visual Studio 代码分析和编译器没有任何报告。

但是当我定义一个枚举时,例如:

public enum DemoEnum
{
    [EnumNote(DemoEnum.Value1, "Some special note about Enum Value1.")]
    Value1 = 1,

    [EnumNote(DemoEnum.Value2, "Some other special note about Enum Value2.")]
    Value2 = 2
}

当我尝试编译它时,VS 会报告每个 EnumNote 构造函数的第一个参数如下:

属性参数必须是常量表达式,typeof 表达式 或属性参数类型的数组创建表达式。

基本上是说 DemoEnum.Value1 和 DemoEnum.Value2 不保持恒定值。我说的对吗?

无论如何,这个错误让我感到困惑,因为这个 Enum 是硬编码的,正如你所见,编译器甚至不必为每个 enum 分配一个值,因为我已经自己做了。

这当然会带来一个问题,我遗漏了什么或误解了什么,以及我应该如何实现提供对每个 EnumNote 被分配到的枚举的引用的目标?

谢谢。

更新:

重新审视之后,我明白为什么 VS 报告枚举不是一个常量表达式,那是因为我指的是一些东西:DemoEnum.Value1 在一个点上,他还没有完成通过 @987654332 @首先给Value1一个定义。但是没有关于如何继续我的这个想法的想法。

更新 2:

在编译后重构 Enum 怎么样,它可能不应该给出任何错误,除非它不能应用于枚举(不记得重构是否适用于枚举),但如果它可以应用它可能会很乱而且很慢吧?

更新 3: 属性包含对分配给它们的枚举的引用的原因。

实际上这是一个非常简单的原因,假设以下情况。假设我有一组自定义属性,出于某种原因,我有时需要知道给定属性属于哪个枚举。

与其编写新代码来确定这一点,为什么不简单地在属性本身中引用给定的枚举呢?这是内存消耗的微小妥协,而在未来,它将节省宝贵的时间来运行任何所需的进程来确定每个属性(甚至只是一个)的给定枚举。

【问题讨论】:

  • 在属性中包含枚举值本身不是多余的吗?恕我直言,仅字符串就足够了,因为该属性已分配给单个枚举值。例如。 [EnumNote("A note for this enum value")]
  • 我已经更新了我的问题,在更新 3 中包含这样的解释。

标签: c# enums custom-attributes


【解决方案1】:

属性参数必须是属性参数类型的常量表达式、typeof表达式或数组创建表达式。

基本上是说 DemoEnum.Value1 和 DemoEnum.Value2 不保持恒定值。我说的对吗?

不完全是。

实际问题似乎是Enum的使用。虽然它主要作为概念类层次结构的基类,但它的处理似乎有点诡计。出于所有意图和目的,它是一个运行时伪类,而不是真正的类。

属性在编译时处理。没有在运行时用属性装饰对象的机制。因此,引入一些运行时技巧来处理 Enum 伪类似乎与 Attributes 函数的方式不兼容。

试试这个:

public class EnumTest : Attribute
{
    public int Value;
    public object Obj;
}

public enum DemoEnum
{
    [EnumTest(Value = (int)DemoEnum.Value1, Obj = DemoEnum.Value1)]
    Value1 = 1,

    [EnumTest(Value = (int)DemoEnum.Value2)]
    Value2 = 2
}

这编译得很好(VS2010 中的 .NET 4.0),并且 Attribute 属性设置正确。我可以检查 Attribute 的 Obj 属性并获得我期望的那种数据。


也就是说......不太确定这会有多大用处。您已经拥有一个正在装饰的值的实例,因此将值本身存储在 Attribute 中似乎有点多余。

编辑:一个可能的解决方案...

在稍微渗透一下之后(我在睡着的时候做了一些最好的思考),我意识到问题出在实际的 parameter 类型上(如@987654321 的回答中所述@) 我们可以通过一些拳击来解决这个问题。

public class EnumTest : Attribute
{
    public Enum enum;

    public EnumTest(object e)
    {
        enum = e as Enum;
    }
}

通过这种方式,您可以从一个对象初始化 Attribute,C# 和 CLR 似乎很容易做到这一点。您失去了使用 Enum 初始化时固有的类型检查,但我相信它可以实现所述目标。

【讨论】:

  • 冗余,可能是的。但这只是一个人的学习方式。除了您所说的在装饰中引用值背后的核心思想之外,主要是为了,将来不需要通过枚举来查找给定属性属于哪个枚举。一个简单的引用比在程序集或命名空间中使用的所有枚举的完整循环更有效,它是后续命名空间来查找一个给定属性属于哪个枚举。我打破“非混合理念”可能是错误的,但这是一个需要时间的学习过程。
  • 如果您将 Enum 视为基类 - 除了 Attribute,它实际上是 - 然后您可以在实例上调用 GetType() 以获取存储在 Enum 变量中的枚举类型:{ Enum e = EnumTest.Value1; Assert.AreEqual(e.GetType().Name, "EnumTest"); }
  • 将参数类型从枚举更改为对象有效,谢谢。
【解决方案2】:

您不能在编译时将值传递给属性构造函数。这是对属性的限制。所以你只能

[EnumNote(1,"Some special note")]
Value1=1,

但是您的目的打破了在 c# 中混合面向方面编程的属性的想法。所以不要用属性来做。

关于属性和面向方面的编程你可以阅读this article

【讨论】:

  • 引用枚举的值肯定更容易,并且随着我计划对 EnumAttribute 类进行的下一次改进,确保将该值转换回正确的 Enum 类型不会有问题。实际上,我必须改进课程的想法,每当请求给定属性时,它都会自我转换回枚举。无论如何,我对你最后的评论更感兴趣,关于打破混合方面,我不熟悉这样的方面,你能告诉我你的意思吗?我会很感激的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 1970-01-01
  • 2023-03-29
相关资源
最近更新 更多