Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
557 views
in Technique[技术] by (71.8m points)

.net - How to read custom attribute parameters and values attached to a class or method? (C#)

I want to "read" the parameters of attributes whether they are attached to a class or to a method, or want to get back the attribute object of a particular class or method. This seems to be not available for all cases.

While I was trying to implement it, i.e.

??1. Read parameters of an attribute, attached to a class. How? (see Question 1)
Parameters are the constructor parameters of the attribute, e.g.
public MyOwnAttribute(params object[] p).

??2. Get attibute object's properties, attached to a method. How? (see Question 2)
In the example attribute MyOwnAttribute, there are MyProperty1 and MyProperty2 defined. So if you apply it to
[MyOwnAttribute("World", "2")]
public void MyMethod2() {...},
how can I read them (the constructor assigns "World" to MyProperty1 and "2" to MyProperty1)?

??3. Read parameters of an attribute, attached to a method. Solved. Example: MyOwnAttribute.GetMethodAttributeValues<clsA>(nameof(clsA.MyMethod2))

??4. Get attribute object's properties, attached to a class. Solved. Example: 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). The SO sidebar shows some interesting links ("Related": Link 1, Link 2, Link 3), but still I couldn't put the missing pieces together.

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?
    (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?
    (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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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. 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.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...