Почему атрибуты C # так ограничены? - PullRequest
6 голосов
/ 21 сентября 2010

Я понимаю, что это время компиляции, поэтому они не могут быть общими и должны быть инициализированы постоянными значениями. Но:
Почему они не могут получить информацию, которую вы получили бы, если бы вы отражали то, к чему они применяются?
Почему они не могут принимать лямбда-выражения, функции или делегаты? Не являются ли функции постоянными для компилятора?

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

Это было что-то напыщенное, но я действительно хочу знать, почему они кажутся такими недоделанными.

Вот что я хотел сделать. Предполагалось, что это API для сопоставления значений из ресурсов через функцию, присвоенную атрибуту свойству, к которому применяется атрибут. Обратите внимание, что абстрактный класс не должен был бы существовать, если бы атрибуты могли знать, что они отражают. Я публикую это, потому что кто-то хотел знать, почему я хотел бы дать функции конструкторам атрибутов, и, возможно, потому, что то, что я пытаюсь сделать, уже сделано.

public delegate void PropertyHandler(object parent, PropertyInfo property, object value);

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FromResourceAttribute : Attribute
{
    private static readonly PropertyHandler m_defaultHandler =  (parent, property, value) => 
                                                                {
                                                                    property.SetValue(parent, value, null);
                                                                };

    public PropertyHandler Handler { get; set; }

    public FromResourceAttribute(PropertyHandler handler)
    {
        Handler = handler;
    }

    public FromResourceAttribute()
    {
        Handler = m_defaultHandler;
    }
}

public abstract class ResourceDependent
{
    public ResourceDependent(ResourceManager resources)
    {
        var resourceDependentProperties = 
            from property in GetType().GetProperties()
            let fromResourceAttributes = property.GetCustomAttributes(typeof(FromResourceAttribute), true)
            where fromResourceAttributes.Count() == 1
            let propertyHandler = ((FromResourceAttribute)fromResourceAttributes.Single()).Handler
            select new { Info = property, Handler = propertyHandler };

        foreach(var property in resourceDependentProperties)
        {
            property.Handler(this, property.Info, resources.GetObject(property.Info.Name));
        }
    }
}

class ResourceDependentTest : ResourceDependent
{
    [FromResource]
    public string Data { get; set; }

    [FromResource((parent, property, value) => property.SetValue(parent, ((string)value).Split('|'), null))]
    public string[] Data2 { get; set; }

    static PropertyHandler Data3Handler =   (parent, property, value) =>
                                            {
                                                //Magic
                                            };

    [FromResource(Data3Handler)]
    public int Data3 { get; set; }

    public ResourceDependentTest() : base(Properties.Resources.ResourceManager)
    {

    }
}

Ответы [ 4 ]

11 голосов
/ 21 сентября 2010

Почему они не могут получить информацию, которую вы получили бы, если бы отразили то, к чему они применяются?

Частично причина в том, что атрибуты не должны применяться ни к чему.Совершенно законно создавать атрибут императивного кода, который ни к чему не привязан.

// Not attached
var attrib = new CLSCompliantAttribute(false);

Почему они не могут принимать лямбда-выражения, функции или делегаты?Разве функции не являются постоянными для компилятора?

Все они сводятся к вопросу о том, почему делегаты не могут быть частью атрибута.По своей сути делегаты состоят из двух частей: 1) экземпляра и 2) указателя на метод.# 1 в значительной степени убивает его, так как экземпляр не является константой и не может быть частью значения атрибута.

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

5 голосов
/ 21 сентября 2010

На самом деле на вопрос о том, почему они не могут быть универсальными, уже был дан ответ, и, по словам Эрика Липперта, они не поддерживаются просто потому, что они добавили бы сложности в язык, и до сих пор это не считалось целесообразным.Это, конечно, не потому, что это время компиляции.В IL вы, очевидно, можете создавать общие атрибуты.( Ссылка .)

Что касается того, почему они не могут принимать лямбда-выражения и так далее, я полагаю, что это та же самая причина.Запрос на использование делегатов был Microsoft Connect с 2006 года. Вы можете проголосовать за него, если хотите.

2 голосов
/ 21 сентября 2010

Короткая, короткая версия заключается в том, что IL не поддерживает больше функций;см. ECMA-335 Раздел II §21 Пользовательские атрибуты и Раздел II §23.3 Пользовательские атрибуты.

Для подведения итогов §23.3 пользовательские атрибуты используют пользовательский формат сериализации , которыйхранится в IL, а не двоичная сериализация , не XML или SOAP сериализация.Цитирование из стандартного §23.3:

FieldOrPropType должен быть точно одним из: ELEMENT_TYPE_BOOLEAN, ELEMENT_TYPE_CHAR, ELEMENT_TYPE_I1, ELEMENT_TYPE_U1, ELEMENT_TYPE_I2, ELEMENT_TYPE_U2, ELEMENT_TYPE_I4, ELEMENT_TYPE_U4, ELEMENT_TYPE_I8, ELEMENT_TYPE_U8, ELEMENT_TYPE_R4, ELEMENT_TYPE_R8, ELEMENT_TYPE_STRING.Одномерный массив с нулями указывается в виде одного байта 0x1D, за которым следует FieldOrPropType типа элемента.(См. §23.1.16) Перечисление указывается в виде одного байта 0x55, за которым следует SerString.followed за SerString.

Очевидный ответ, конечно же, таков: «Почему не ILссылки на методы поддержки формата сериализации / и т. д. И очевидный ответ, конечно, заключается в том, что они чувствовали, что в этом нет необходимости, и / или это приведет к дальнейшему раздутию IL.

(Интересное замечание: ссылки на типы фактически реализованыиспользуя строку, содержащую полное имя сборки типа. По той же логике я предполагаю, что ссылку на метод можно «закодировать», используя имя типа и кодировку для метода, но я подозреваю, что это будет «хрупким»", в том смысле, что добавление / изменение методов может привести к поломке.)

1 голос
/ 21 сентября 2010

Мне не очень нравятся атрибуты (потому что, по моему мнению, они созданы для сборщиков инструментов, таких как nunit), но я думаю, что вы уже ответили на свой вопрос: Атрибуты являются постоянной времени компиляции

Параметры атрибута ограничены постоянные значения следующих Типы:

* Simple types (bool, byte, char, short, int, long, float, and double)
* string
* System.Type
* enums
* object (The argument to an attribute parameter of type object

должно быть постоянным значением одного из вышеуказанные типы.) * Одномерные массивы любого из вышеперечисленных типов

http://msdn.microsoft.com/en-us/library/aa288454%28VS.71%29.aspx#vcwlkattributestutorialanchor1

в то время как возвращаемое значение лямбды, делегаты и функции не являются.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...