5

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

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

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

首先,我为自定义属性编写了一个基类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在某个点上,他还没有完成第一个DemoEnum定义Value1地方。然而,没有关于如何继续我的这个想法的想法。

更新 2:

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

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

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

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

4

2 回答 2

11

属性参数必须是属性参数类型的常量表达式、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 属性设置正确。我可以检查ObjAttribute 的属性并获得我期望的那种数据。

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

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

在让它渗透一点之后(我在睡着时做了一些我最好的思考),我意识到由于问题出在实际参数类型上(如该问题的答案中所述,我们可以稍微解决这个问题的拳击。

public class EnumTest : Attribute
{
    public Enum enum;

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

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

于 2013-02-14T05:27:47.983 回答
1

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

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

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

关于属性和面向方面的编程你可以阅读 这篇文章

于 2013-02-14T04:50:59.793 回答