c# - 枚举作为其自己的自定义属性构造函数的参数

标签 c# enums custom-attributes

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

因此,我为 Enum 编写了一些扩展方法,以便轻松检索此类属性,例如:DemoEnum.Value1.GetAttribute<EnumNote>() .

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

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

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 的第一个参数构造函数如下:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.

基本上是说 DemoEnum.Value1 和 DemoEnum.Value2 不保存常量值。我说得对吗?

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

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

谢谢。

更新:

重新审视后,我明白为什么 VS 报告枚举不是常量表达式,那是因为我指的是:DemoEnum.Value1在某一点上,他还没有完成DemoEnumValue1下定义首先。然而,不知道如何继续我的这个想法。

更新2:

在编译后重构枚举怎么样,它可能不会给出任何错误,除非它不能应用于枚举(不记得重构是否适用于枚举),但如果可以的话应用它可能会很麻烦并且很慢,对吗?

更新 3:属性包含对其分配到的枚举的引用的原因。

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

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

最佳答案

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.

基本上是说 DemoEnum.Value1 和 DemoEnum.Value2 不保存常量值。我说得对吗?

不完全是。

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

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

试试这个:

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 属性设置正确。我可以检查属性的 Obj 属性并获取我期望的数据类型。

<罢工><意见>
也就是说……不太确定这会有多大用处。您已经必须拥有要装饰的值的实例,因此将值本身存储在属性中似乎有点多余。

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

在让这个渗透一点之后(我在 sleep 时做了一些最好的思考),我意识到问题出在实际的参数类型上(如 this question 的答案中所述)我们可以通过一些拳击来解决这个问题。

public class EnumTest : Attribute
{
    public Enum enum;

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

通过这种方式,您可以从对象初始化属性,C# 和 CLR 似乎可以轻松完成此操作。您失去了使用枚举初始化时固有的类型检查,但我相信它实现了既定的目标。

关于c# - 枚举作为其自己的自定义属性构造函数的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14867793/

相关文章:

c# - 为什么我的 .NET 应用程序在从网络驱动器运行时会崩溃?

c# - 动态连接和缩小 JavaScript 或在构建时 - ASP.NET MVC

c# - 将附加信息与 .NET 枚举相关联

asp.net - 如何制作可配置的 DisplayFormat 属性

c# - 如何在消息框中显示由sql查询打印的值

c# - 从包内读取 SSIS 包文件名(包部署)

java - 如何将枚举的所有值显示为 <option> 元素?

class - Kotlin 为枚举类值方法定义接口(interface)

c# - 自定义验证属性调用另一个验证属性

C# DataAnnotations 和资源文件 - 为什么没有简单的构造函数?