在自己的自定义属性构造函数中将Enum作为参数 - c#

在这里,我花了一些时间来学习有关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是硬编码的,并且正如您所看到的,由于我自己已经完成了编译工作,因此编译器甚至不必为每个枚举赋值。

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

谢谢。

更新:

重新看一下后,我了解了为什么VS报告的枚举不是一个常量表达式,那是因为我指的是:DemoEnum.Value1在某种程度上,他还没有完成通过DemoEnum给出的首先是Value1的定义。但是,没有关于如何继续我的想法的想法。

更新2:

那么在编译完Enum之后如何重构它,除非它不能应用于枚举(不记得重构是否适用于枚举),否则它可能不应该给出任何错误,但是如果可以应用它将可能很杂乱,慢了吧?

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

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

与其编写新代码来确定这一点,不如不直接在Attribute本身中引用给定的Enum?这是对内存消耗的微小折衷,而在将来,它将节省运行任何必需的过程来确定每个属性(甚至只是一个)的给定枚举数的宝贵时间。

参考方案

属性参数必须是属性参数类型的常量表达式,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中似乎有点多余。

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

让它渗透一些之后(我在睡着时做了一些最好的思考),我意识到,既然问题出在实际的参数类型上(如在this question的答案中提到的),我们可以解决一个问题。一点拳击。

public class EnumTest : Attribute
{
    public Enum enum;

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

这样,您可以从一个对象初始化Attribute,而C#和CLR看起来很舒服。您会丢失使用Enum初始化时固有的类型检查,但是我相信它可以达到指定的目的。

LeetCode题解计算机为什么是基于二进制的?

可以是三进制么?二进制有什么好处?题解:为什么叫电子计算机?算盘应该没有二进制

LeetCode题解统计城市的所有灯泡

这个是我刚毕业的时候,一个真实的面试题,这是一个开放题。题目描述:想办法,将一个城市的所有灯泡数量统计出来。题解:费米估算法1、如果某个城市常驻人口有1000万2、假设每5人居住在一套房里,每套房有灯泡5只,那么住宅灯泡共有1000万只3、假设公众场所每10人共享一只灯泡,那么共有100万只4、主要的这两者相加就得出了1100万只当然实际上这是估算的,具体应…

LeetCode题解黑白圆盘

一个圆盘被涂上了黑白二色,两种颜色各占一个半圆。圆盘以一个未知的速度、按一个未知的方向旋转。你有一种特殊的相机可以让你即时观察到圆上的一个点的颜色。你需要多少个相机才能确定圆盘旋转的方向?题解:可以用一个相机即可

LeetCode题解圆上任取三点构成锐角三角形的概率

来自字节跳动的一道几何题题解:1/4

LeetCode题解深度优先遍历和回溯的关系?

深度优先遍历的范围更大还是回溯的范围更大?为什么?题解:我的理解是:dfs是回溯思想的一种体现- 回溯:是在整个搜索空间中搜索出可行解,在搜索过程中不断剪枝回退,这是回溯的思想,这个搜索空间并没有限制于特定的数据结构。- dfs:dfs是指特定的数据结构中如图,树(特殊的图)中搜索答案,范围限制在了特定的数据结构。个人拙见。