如何从属性中获取命名参数的构造函数

How to get constructor named arguments from attribute

我和this question有同样的问题。问题是,即使在属性的构造函数中使用命名参数,我仍然得到一个空集合。

这是我的属性定义:

public class MenuItemAttribute : Attribute
{
    ApplicationCategoryEnum ApplicationCategory { get; }
    string ControllerDisplayName { get; }
    bool IsDefaultRoute { get; }

    public MenuItemAttribute(ApplicationCategoryEnum applicationCategory, string controllerDisplayName, bool isDefaultRoute)
    {
        ControllerDisplayName = controllerDisplayName;
        ApplicationCategory = applicationCategory;
        IsDefaultRoute = isDefaultRoute;
    }
}

这就是我的使用方式:

[MenuItem(
    applicationCategory: ApplicationCategoryEnum.CONTROLPANEL,
    controllerDisplayName: "Account Management",
    isDefaultRoute: false)]
public class AccountController : Controller { /// }

这是我通过控制器的属性的方式:

var attributeData = controllerInfo
    .CustomAttributes
    .FirstOrDefault(attrs => attrs.AttributeType == typeof(MenuItemAttribute))
    .NamedArguments;

如果我使用 ConstructorArguments 而不是 NamedArguments,我可以看到参数在那里。

我错过了什么?

目前您所有的参数都是位置参数,因此它们在 ConstructorArguments 中返回。

docs中所写:

Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class.

将您的 MenuItemAttribute 更改为例如:

    public class MenuItemAttribute : Attribute
    {
        ApplicationCategoryEnum ApplicationCategory { get; }
        public string ControllerDisplayName { get; set; }
        public bool IsDefaultRoute { get; set; }

        public MenuItemAttribute(ApplicationCategoryEnum applicationCategory)
        {
            ApplicationCategory = applicationCategory;
        }
    }

和用法

[MenuItem(ApplicationCategoryEnum.CONTROLPANEL, ControllerDisplayName = "asdsa", IsDefaultRoute = true)]

会给你 NamedArguments 集合中的 2 个元素。

语法:

[MenuItem(
    applicationCategory: ApplicationCategoryEnum.CONTROLPANEL,
    controllerDisplayName: "Account Management",
    isDefaultRoute: false)]

表示构造函数参数;您想要的数据在 ConstructorArguments 成员中:

var attrib = typeof(AccountController)
    .CustomAttributes
    .FirstOrDefault(attrs => attrs.AttributeType == typeof(MenuItemAttribute));
if (attrib is object)
{
    var declared = attrib.Constructor.GetParameters();
    var values = attrib.ConstructorArguments;
    for (int i = 0; i < values.Count; i++)
    {
        Console.WriteLine($"{declared[i].Name}={values[i].Value}");
    }
}

(NamedArguments 用于涉及 = 的 ever-so-subtly-different 用法,即 IsDefaultRoute = true 调用 IsDefaultRoute [=28] 的 property-setter =] 的值为 true)