【问题标题】:.NET Attributes: Why does GetCustomAttributes() make a new attribute instance every time?.NET 属性:为什么 GetCustomAttributes() 每次都创建一个新的属性实例?
【发布时间】:2009-01-06 16:47:04
【问题描述】:

所以我在 .NET 中使用了更多属性,并意识到每次调用 Type.GetCustomAttributes() 都会创建我的属性的一个新实例。这是为什么?我认为属性实例基本上是一个单例每个成员信息,其中 1 个实例绑定到类型、PropertyInfo 等......

这是我的测试代码:

using System;

namespace AttribTest
{
[AttributeUsage(AttributeTargets.Class)]
class MyAttribAttribute : Attribute
{
    public string Value { get; set; }

    public MyAttribAttribute()
        : base()
    {
        Console.WriteLine("Created MyAttrib instance");
    }
}

[MyAttrib(Value = "SetOnClass")]
class MyClass
{
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Getting attributes for MyClass.");
        object[] a = typeof(MyClass).GetCustomAttributes(false);
        ((MyAttribAttribute)a[0]).Value = "a1";

        Console.WriteLine("Getting attributes for MyClass.");
        a = typeof(MyClass).GetCustomAttributes(false);
        Console.WriteLine(((MyAttribAttribute)a[0]).Value);

        Console.ReadKey();
    }
}
}

现在如果 I 要实现属性,我希望输出是:

Created MyAttrib instance
Getting attributes for MyClass.
Getting attributes for MyClass.
a1

“类加载器”(对不起,我有更多的 Java 背景,不是 100% 确定 .net 如何加载其类型)将编译 MyClass,并创建 MyAttribAttribute 的实例,并将它们一起存储在某个地方。 (如果这是 Java,可能是堆中的 Perm Gen)然后对 GetCustomAttributes() 的 2 次调用将返回相同的早先创建的实例。

但实际输出是:

Getting attributes for MyClass.
Created MyAttrib instance
Getting attributes for MyClass.
Created MyAttrib instance
SetOnClass

那么……为什么?似乎为每次调用创建所有这些对象的新实例有点过分,并且不利于性能/内存管理。有什么方法可以一遍又一遍地获取相同的实例?

有人知道为什么要这样设计吗?

我完全关心的原因是因为我创建了一个内部保存一些验证信息的自定义属性,所以在属性中我基本上有一个“private bool Validated”,我设置为 true。验证的东西需要一段时间,所以我不想每次都运行它。现在的问题是,因为每次我获取属性时它都会创建一个新的属性实例,所以 Validated 总是“假”。

【问题讨论】:

    标签: .net performance attributes


    【解决方案1】:

    属性不作为对象存储在内存中,它们仅作为元数据存储在程序集中。当您查询它时,它将被构造并返回,并且通常属性是一次性对象,因此运行时保留它们以防万一您再次需要它们可能会浪费大量内存。

    简而言之,您需要找到另一种方式来存储您的共享信息。

    这是属性上的documentation

    【讨论】:

    • 链接失效
    【解决方案2】:

    对象创建很便宜。

    如果你有类似的属性

    public class MyAttribute : Attribute {
        public virtual string MyText { get; set; }
    }
    

    并将其应用于类似的类

    [MyAttribute(MyText="some text")]
    public class MyClass {
    }
    

    你检索到一个喜欢

    var attr =
        typeof(MyClass).GetCustomAttributes(typeof(MyAttribute), false)
        .Cast<MyAttribute>().Single();
    

    你在它上面设置了一些属性

    attr.MyText = "not the text we started with";
    

    应该发生什么,发生什么,下次你打电话时

    Console.WriteLine(
        typeof(MyClass).GetCustomAttributes(typeof(MyAttribute), false)
        .Cast<MyAttribute>().Single().Name
    );
    

    ?

    【讨论】:

    • 同意 - 我认为可变性是真正的问题。
    • 我同意可变性是一个问题。如果属性不是可变的,那么这将支持将单例存储在 mem 中的情况,因为它总是相同的,并且无论如何可能比元数据占用更少的空间。
    • 我仍然没有看到单身人士的情况。对象创建很便宜。如果由于某种原因有两个代表相同概念事物的实例会产生不正确的行为,我们将需要一个单例。
    • 我有一个属性可以验证日期是否大于 DateTime.Now...如果每次调用 GetCustomAttributes 时都没有初始化它,它将无法工作...因为而不是验证日期现在它将根据系统启动时间验证它......
    • 每次对象创建后都会进行昂贵的垃圾回收
    【解决方案3】:

    这是因为属性保存在元数据中。 属性应该用于诸如“用户友好的属性名称”等信息......

    【讨论】:

    • 尽管我只是将“用户友好名称”存储在一个属性中,但每次我查找该属性时,运行时都会创建一个新名称。因此,只是频繁地查找属性,而不考虑属性内容,可能会变得很昂贵。
    • 是的,可以。但如果你经常这样做,可能有比这更好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多