Использование методов атрибута C # - PullRequest
0 голосов
/ 12 марта 2019

В C # каково назначение методов, объявленных в атрибутах, и как они используются?

В качестве примера рассмотрим атрибут MaxLengthAttribute: он имееткуча методов.Одним из них является метод IsValid(), который используется для проверки свойства, к которому применяется атрибут.Как выполняется эта проверка?Я предполагаю, что метод IsValid() вызывается для свойства, но я не нахожу документацию о том, как вызывать методы атрибутов.

Примечание: у меня есть фон Java.В Java аннотации предназначены как метаданные и объявляются как @inteface s, поэтому у них нет методов.

Ответы [ 3 ]

2 голосов
/ 12 марта 2019

Почти во всех случаях ответ прост: вручную, но не по вашему коду.Некоторая часть кода в какой-то платформе, которую вы используете, преднамеренно проверяет эти атрибуты, а затем , если они существуют : материализует их (предпочтительно также с некоторым типом кэширования) и вызывает метод.

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

using System;

[SomeAttribute("boop")]
static class P
{
    static void Main()
    {
        var obj = (SomeAttribute)Attribute.GetCustomAttribute(
            typeof(P), typeof(SomeAttribute));

        // note the attribute doesn't know the context
        // so we need to pass that *in*; an attribute
        // doesn't know what it has been attached to
        obj?.DoSomething(typeof(P));
    }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct
    | AttributeTargets.Enum)]
class SomeAttribute : Attribute
{
    public string Name { get; }
    public SomeAttribute(string name)
        => Name = name;
    public void DoSomething(Type type)
        => Console.WriteLine($"hey {type.Name} - {Name}");
}
1 голос
/ 12 марта 2019

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

Итак, представьте, что у вас есть этот код:

[MyAttribute]
class MyClass
{
}

class MyAttribute : Attribute
{
    public void DoSomething();
}

Теперь у вас есть код, который проверяет наличие атрибута и, если да, вызывает DoSomething:

// get types with the attribute
var typesAndAttributes= myAssembly.GetTypes().Select(x => new 
    { 
        Type = x, 
        Attribute = Attribute.GetCustomAttribute(x, typeof(MyAttribute)) 
    });

// now call DoSomething for every attribute
forerach(var e in typesAndAttributes)
{
    e.Attribute?.DoSomething();
}

В вашем примере MaxLengthAttribute это означает следующее. Если вы украсите своего члена так:

MaxLengthAttribute(2)
public int[] MyArr = new int[3];

и выполнить код, который фреймворк вызывает IsValid для MyArr и, вероятно, (не уверен в этом, не проверял исходный код) вернет false, так как значение содержит 3 элемента, хотя только два считаются действительными.

0 голосов
/ 12 марта 2019

В качестве примера рассмотрим атрибут MaxLengthAttribute: в нем есть несколько методов. Одним из них является метод IsValid (), который используется для проверки свойства, к которому применяется атрибут. Как выполняется эта проверка? Я предполагаю, что метод IsValid () вызывается для свойства, но я не нахожу документацию о том, как вызывать методы атрибута.

Вот очень простой пример:

// Start off with an object we're going to validate
public class Foo
{
    [MaxLength(5)]
    public string Bar { get; set; } 
}

var objectToValidate = new Foo() { Bar = "123456" };

// Use reflection to get a list of properties on the object
var properties = objectToValidate.GetType().GetProperties();

foreach (var property in properties)
{
    // For each property, get the attributes defined on that property
    // which derive from the ValidationAttribute base class
    var attributes = property.GetCustomAttributes<ValidationAttribute>();

    var propertyValue = property.GetValue(objectToValidate);

    foreach (var attribute in attributes)
    {
        // For each attribute, call its IsValid method, passing in the value
        // of the property
        bool isValid = attribute.IsValid(propertyValue);
        if (!isValid)
        {
            Console.WriteLine("{0} is invalid", property.Name); 
        }
    }
}

Это более или менее то, что делает Validator.ValidateObject, за исключением гораздо большего кеширования.

(В случае методов DataAnnotations фактически используется инфраструктура TypeDescriptor . Это позволяет эффективно добавлять атрибуты к классам и их свойствам без непосредственного изменения источника класса).

Пример выполнения

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