Атрибуты .NET:Почему GetCustomAttributes() каждый раз создает новый экземпляр атрибута?

StackOverflow https://stackoverflow.com/questions/417275

  •  03-07-2019
  •  | 
  •  

Вопрос

Итак, я еще немного поигрался с атрибутами в .NET и понял, что каждый вызов Type.GetCustomAttributes() создает новый экземпляр моего атрибута.Почему это?Я бы подумал, что экземпляр атрибута в основном будет представлять собой Singleton-per-MemberInfo, с 1 экземпляром, привязанным к Type, 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();
    }
}
}

Сейчас если я Если бы мы реализовали атрибуты, я бы ожидал, что результат будет:

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

Где «загрузчик классов» (извините, у меня больше опыта работы с Java, но я не уверен на 100%, как .net загружает его типы) скомпилирует MyClass, создаст экземпляр MyAttribAttribute и сохранит их где-нибудь вместе.(вероятно, Perm Gen в куче, если бы это была Java). Два вызова GetCustomAttributes() тогда просто вернут тот же ранее созданный экземпляр.

Но фактический результат:

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

Так...почему?Кажется, что создание нового экземпляра всех этих объектов для каждого вызова немного излишне и не очень хорошо для управления производительностью/памятью.Есть ли способ всегда получать один и тот же экземпляр снова и снова?

У кого-нибудь есть идеи, почему это было спроектировано таким образом?

Причина, по которой меня это вообще волнует, заключается в том, что я создал собственный атрибут, который внутри содержит некоторую информацию для проверки, поэтому в атрибуте у меня в основном есть «private bool Validated», которому я установил значение true.Проверка занимает некоторое время, поэтому я не хочу запускать ее каждый раз.Теперь проблема в том, что, поскольку он создает новый экземпляр атрибута каждый раз, когда я получаю атрибуты, Validated всегда имеет значение «ложь».

Это было полезно?

Решение

Создание объектов обходится дешево.

Если у вас был атрибут типа

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
);

?

Другие советы

Атрибуты не хранятся в памяти как объекты, они только хранятся в виде метаданных в сборке. Когда вы запросите его, он будет сконструирован и возвращен, и обычно атрибуты являются одноразовыми объектами, поэтому для среды выполнения их нужно хранить на всякий случай, если они вам понадобятся снова, вероятно, будут тратить много памяти.

Короче говоря, вам нужно найти другой способ хранения вашей общей информации.

Вот документация на атрибуты.

Это потому, что атрибуты сохраняются в метаданных. Атрибуты следует использовать для такой информации, как «удобное для пользователя имя свойства» и т. Д.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top