给定一组属性,如何确定最匹配的构造函数

How to determine the best-matched constructor, given a set of properties

虽然可以通过反射查询应用于任何 class 的属性,但无法确定在编译时调用了哪个构造函数重载。在我的场景中,我正在分析一个程序集中的所有类型,这些类型具有如下应用的属性 [TestAttribute]

[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class TestAttribute: Attribute
{
    public string Name { get; } = "";
    public string NameDisplay { get; } = "";
    public string Description { get; set; } = "";

    public TestAttribute () { }
    public TestAttribute (string name) { this.Name = name; }
    public TestAttribute (string name, string nameDisplay) : this (name) { this.NameDisplay = nameDisplay; }
    public TestAttribute (string name, string nameDisplay, string description) : this (name, nameDisplay) { this.Description = description; }
}

[TestAttribute()]
[TestAttribute ("_Name")]
[TestAttribute ("_Name_", "_NameDisplay_")]
[TestAttribute ("_Name_", "_NameDisplay_", "_Description_")]
public class TestClass { }

objective 用于生成声明 class TestClass 并应用正确属性的代码,并将其发送到新程序集中。现在,由于属性声明语法丢失到运行时,我只能查询属性特性。但是,请注意某些特性属性如何没有设置器。此外,构造函数参数的名称和顺序与它们设置的内部属性之间没有关联。

var type = typeof (TestClass);
var attributes = type.GetCustomAttributes(typeof(TestAttribute), inherit: false).Cast<Attribute>();

foreach (var attribute in attributes)
{
    var attributeType = attribute.GetType();
    var constructors = attributeType.GetConstructors().OrderByDescending (c => c.GetParameters().Length);
    var attributeName = attributeType.Name.Substring (0, attributeType.Name.Length - nameof (Attribute).Length);
    var properties = attributeType
        .GetProperties (BindingFlags.Instance | BindingFlags.Public)
        .Where (p => p.CanRead)
        .Where (p => p.GetGetMethod (nonPublic: false) != null)
        .Where (p => ((p.PropertyType.IsValueType) || (p.PropertyType == typeof (string))))
        .ToList();

    foreach (var constructor in constructors)
    {
        var parameters = constructor.GetParameters().ToList();

        if (parameters.Any())
        {
            // Should write: [TestAttribute ("_Name_", "_NameDisplay_", "_Description_")]
            Console.WriteLine($@"[{attributeName} (???????)]");
        }
        else
        {
            // Correct.
            Console.WriteLine($@"[{attributeName}]");
        }
    }
}

缺少通过错误处理尝试所有排列的粗暴方法,我如何可靠地重新创建代码如下:

[TestAttribute()]
[TestAttribute ("_Name")]
[TestAttribute ("_Name_", "_NameDisplay_")]
[TestAttribute ("_Name_", "_NameDisplay_", "_Description_")]
public class TestClass { }

如有任何建议,我们将不胜感激。

System.Reflection.CustomAttributeData class 提供有关使用的构造函数、CustomAttributes 的命名和位置参数的信息。

您可以使用 CustomAttributeData.GetCustomAttributes(...)typeof(...).GetCustomAttributesData() 作为起点。