简体   繁体   English

如何读取附加到类或方法的自定义属性参数和值? (C#)

[英]How to read custom attribute parameters and values attached to a class or method? (C#)

As you know, custom attributes can be "attached to" a class or to a method (I am not regarding restrictions here - I know you can restrict it to classes or methods).如您所知,自定义属性可以“附加到”一个类或一个方法(我在这里不涉及限制 - 我知道您可以将其限制为类或方法)。

I want to "read" the parameters of attributes whether they are attached to a class or to a method, or I want to get back the attribute object of a particular class or method.我想“读取”属性的参数,无论它们是附加到一个类还是一个方法,或者我想取回特定类或方法的属性对象。

While I was trying to implement it, ie当我试图实现它时,即

1. Read parameters of an attribute, attached to a class. 1. 读取属性的参数,附加到类。 How?如何? (see Question 1) (见问题 1)
Parameters are the constructor parameters of the attribute, eg参数是属性的构造函数参数,例如
public MyOwnAttribute(params object[] p) . public MyOwnAttribute(params object[] p)

2. Get attibute object's properties, attached to a method. 2. 获取属性对象的属性,附加到一个方法。 How?如何? (see Question 2) (见问题 2)
In the example attribute MyOwnAttribute , there are MyProperty1 and MyProperty2 defined.在示例属性MyOwnAttribute ,定义了MyProperty1MyProperty2 So if you apply it to所以如果你把它应用到
[MyOwnAttribute("World", "2")]
public void MyMethod2() {...} , public void MyMethod2() {...} ,
how can I read them (the constructor assigns "World" to MyProperty1 and "2" to MyProperty1 )?我如何读取它们(构造函数将"World"分配给MyProperty1并将"2"分配给MyProperty1 )?

3. Read parameters of an attribute, attached to a method. 3. 读取附加到方法的属性的参数 Solved.解决了。 Example: MyOwnAttribute.GetMethodAttributeValues<clsA>(nameof(clsA.MyMethod2))示例: MyOwnAttribute.GetMethodAttributeValues<clsA>(nameof(clsA.MyMethod2))

4. Get attribute object's properties, attached to a class. 4. 获取属性对象的属性,附加到一个类。 Solved.解决了。 Example: MyOwnAttribute.GetClassAttributes(typeof(clsA)).MyProperty1示例: MyOwnAttribute.GetClassAttributes(typeof(clsA)).MyProperty1

I noticed that I couldn't implement it for all 4 cases, I couldn't implement it for cases 1. and 4. The code I wrote for cases 2. and 3. is working fine (I removed it since you now have Tobias' answer for all 4 cases).我注意到我无法为所有 4 个案例实现它,我无法为案例 1. 和案例 4 实现它。我为案例 2. 和 3. 编写的代码工作正常(我删除了它,因为你现在有了 Tobias ' 对所有 4 种情况的回答)。 The SO sidebar shows some interesting links ("Related": Link 1 , Link 2 , Link 3 ), but still I couldn't put the missing pieces together. SO 侧边栏显示了一些有趣的链接(“相关”: 链接 1链接 2链接 3 ),但我仍然无法将丢失的部分放在一起。

Consider the following custom attribute:考虑以下自定义属性:

public class MyOwnAttribute : Attribute
{

    public string MyProperty1 { get; set; }
    public string MyProperty2 { get; set; }

    // simple case, to make explaining it easier
    public MyOwnAttribute(string p1 = null, string p2 = null)
    {
        MyProperty1 = p1?.ToString();
        MyProperty2 = p2?.ToString();
    }

}

Or I could have the properties defined like:或者我可以定义如下属性:

    public string[] MyProperties { get; set; }

    // allows any number of properties in constructor
    public MyOwnAttribute(params object[] p)
    {
        MyProperties = p.Select(s => s.ToString()).ToArray();
    }

But I couldn't figure out how you could implement this:但我无法弄清楚如何实现这一点:

  • Question 1: How can I access the list of attribte's parameter values attached to a class ?问题 1:如何访问附加到的属性参数值列表?
    (from the attribute's constructor, like implemented for the methods) (来自属性的构造函数,就像为方法实现的一样)
    Example:例子:
    var classAttribParamValues = MyOwnAttribute.GetClassAttributeValues(typeof(clsA));
    string.Join(' ', classAttribParamValues.Select(s => s ?? "")).Dump();

  • Question 2: How can I access attribute's properties attached to a method ?问题 2:如何访问附加到方法的属性的属性?
    (like implemented for the class) (就像为班级实现的那样)
    Example:例子:
    var methodInfo = MyOwnAttribute.GetMethodAttributes<clsA>(nameof(clsA.MyMethod2));
    methodInfo.MyProperty1.Dump();

Does anyone have an idea how that can be done?有谁知道如何做到这一点? Many thanks in advance.提前谢谢了。

Edit:编辑:

After some clarifications here's what I suspect you want to have:经过一些澄清后,我怀疑您想要的是:

public static class AttributeHelper {

    public static TAttribute GetClassAttribute<TTarget, TAttribute>() where TAttribute : Attribute
        => typeof(TTarget).GetAttribute<TAttribute>();

    public static object[] GetClassAttributeValues<TTarget, TAttribute>() where TAttribute : Attribute
        => typeof(TTarget).GetAttributeValues<TAttribute>();

    public static TAttribute GetMethodAttribute<TTarget, TAttribute>(string methodName) where TAttribute : Attribute
        => typeof(TTarget).GetMethod(methodName)?.GetAttribute<TAttribute>();

    public static object[] GetMethodAttributeValues<TTarget, TAttribute>(string methodName) where TAttribute : Attribute
        => typeof(TTarget).GetMethod(methodName)?.GetAttributeValues<TAttribute>();

    private static TAttribute GetAttribute<TAttribute>(this MemberInfo memberInfo) where TAttribute : Attribute
        => memberInfo?.GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault();

    private static object[] GetAttributeValues<TAttribute>(this MemberInfo memberInfo) where TAttribute : Attribute
        => memberInfo
            ?.GetCustomAttributesData()
            .FirstOrDefault(d => d.AttributeType == typeof(TAttribute))
            ?.ConstructorArguments
            .Select(argument => argument.Value)
            .SelectMany(a => a is ReadOnlyCollection<CustomAttributeTypedArgument> p ? p.Select(c => c.Value) : new[] { a })
            .ToArray();
}

The methods are all static now and AttributeHelper no longer derives from Attribute, as you would have to provide the attribute type anyway as a parameter to the methods.这些方法现在都是静态的,并且 AttributeHelper 不再从 Attribute 派生,因为无论如何您都必须提供属性类型作为方法的参数。 As a second parameter simply provide the class on which you expect the attribute.作为第二个参数,只需提供您期望属性的类。

I took some time to reorganize the code as it was quite hard to read for me.我花了一些时间来重新组织代码,因为它对我来说很难阅读。 Perhaps it's a little bit easier to read for you as well.也许它对你来说也更容易阅读。

Example calls:示例调用:

AttributeHelper.GetClassAttributeValues<clsA, MyOwnAttribute>().Dump("1.");

AttributeHelper.GetMethodAttribute<clsA, 
                        MyOwnAttribute>(nameof(clsA.MyMethod2)).Dump("2.");

AttributeHelper.GetMethodAttributeValues<clsA,
                        MyOwnAttribute>(nameof(clsA.MyMethod2)).Dump("3.");

AttributeHelper.GetClassAttribute<clsA,MyOwnAttribute>().Dump("4.");

Old Answer below:旧答案如下:

I think what you are trying to achieve could be solved with an additional protected abstract method in AttributeHelper with a return type of string[] , this would make AttributeHelper abstract as well, but that should be no problem.我认为您要实现的目标可以通过 AttributeHelper 中的附加protected abstract方法来解决,返回类型为string[] ,这也会使 AttributeHelper 抽象,但这应该没问题。

Your deriving Attributes would be forced to implement this new method (if they are not abstract themselves).您的派生属性将被迫实现这个新方法(如果它们本身不是抽象的)。 The Implementation would have to return an array of the values of the attributes properties.实现将必须返回属性值的数组。

Another approach could be to iterate over the PropertyInfos of your Attribute type and read the Properties that way.另一种方法可能是遍历您的 Attribute 类型的 PropertyInfos 并以这种方式读取 Properties。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM