【问题标题】:How to get constructor named arguments from attribute如何从属性中获取构造函数命名参数
【发布时间】:2021-02-18 03:16:09
【问题描述】:

我和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 { /// }

这是我通过Controller的属性的方式:

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

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

我错过了什么?

【问题讨论】:

  • 属性的属性不应该是公开的吗?
  • @Miamy 技术上不需要

标签: c# reflection arguments


【解决方案1】:

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

docs中所写:

属性类的每个非静态公共读写字段和属性都为属性类定义了一个命名参数。

将您的 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 个元素。

【讨论】:

    【解决方案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 用于涉及= 的极其微妙的不同用法,即IsDefaultRoute = true 调用IsDefaultRoute 属性的属性设置器,其值为true

    【讨论】:

    • 所以不能从同一个对象访问参数名和参数值?
    • @DavideVitali 没有; API 知道参数名称可从 .Constructor 获得,因此它不会尝试为您复制该信息;最终,构造函数参数实际上并不是按名称设置的——它们是按位置设置的(C# 编译器在烘焙元数据之前根据需要移动它们)
    • @DavideVitali 您可以更详细地看到这一点in this example,它显示了实际的 IL - 没有 arg 名称,只需键入可以解释为值的二进制原始转储
    猜你喜欢
    • 2020-11-08
    • 1970-01-01
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2021-07-06
    相关资源
    最近更新 更多