Проверка атрибута C # - это значение, равное аргументу конструктора и получение значений конструктора - PullRequest
0 голосов
/ 17 декабря 2018

Как я могу проверить, что некоторая строка равна аргументу "конструктора" атрибута?А как получить все значения конструктора (TestArg1, TestArg2)?

struct MyData
{
    [MyAttr("TestArg1", "TestArg2")] //check that some string equals TestArg1/TestArg2
    public string TestArg;
}

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

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

public class MyAttrAttribute : Attribute
{
    public string[] AllowedValues { get; }
    public MyAttrAttribute(params string[] values)
    {
        AllowedValues = values;
    }
}

Вы можете изменить свое поле на свойство с полем поддержки.Это позволяет вам переопределить метод set и выполнить там проверку:

private string _testArg;

[MyAttr("TestArg1", "TestArg2")] //check that some string equals TestArg1/TestArg2
public string TestArg
{
    get => _testArg;

    set
    {
        var allowedValues = this.GetType() //Get the type of 'this'
            .GetProperty(nameof(TestArg)) // Get this property
            .GetCustomAttribute<MyAttrAttribute>() // Get the attribute
            .AllowedValues; //Get the allowed values specified in the attribute

        if(!allowedValues.Contains(value))
        {
            throw new ArgumentOutOfRangeException(nameof(value), 
                $"The value '{value}' is not allowed");
        }
        _testArg = value;
    }
}

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

0 голосов
/ 18 декабря 2018

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

//The attribute we're looking at
public class MyAtt : System.Attribute
{
    public string name;
    public string anotherstring;

    public MyAtt(string name, string anotherstring)
    {
        this.name = name;
        this.anotherstring = anotherstring;
    }
}

public static class Usage
{
    [MyAtt("String1", "String2")] //Using the attribute
    public static string SomeProperty = "String1";
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine(IsEqualToAttribute("String1"));
        Console.WriteLine(IsEqualToAttribute("blah"));
        Console.ReadKey();
    }

    public static bool IsEqualToAttribute(string mystring)
    {
        //Let's get all the properties from Usage
        PropertyInfo[] props = typeof(Usage).GetProperties();
        foreach (var prop in props)
        {
            //Let's make sure we have the right property
            if (prop.Name == "SomeProperty")
            {
                //Get the attributes from the property
                var attrs = prop.GetCustomAttributes();

                //Select just the attribute named "MyAtt"
                var attr = attrs.SingleOrDefault(x => x.GetType().Name == "MyAtt");
                MyAtt myAttribute = attr as MyAtt; //Just casting to the correct type
                if (myAttribute.name == mystring) //Compare the strings
                    return true;
                if (myAttribute.anotherstring == mystring) //Compare the strings
                    return true;
            }
        }

        return false;
    }
}

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

Более подробная информация может быть найдена здесь: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/accessing-attributes-by-using-reflection

Поскольку получение свойств конструктора что-то в соответствии с

typeof(MyAtt).GetConstructor().GetParameters()

Получит сведения о параметре дляКонструктор.

В документации Microsoft также есть информация об этом: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.customattributedata.constructor?view=netframework-4.7.2

...