如何读取属性参数和值(class属性或方法属性)?
How to read attribute parameters and values (class attributes or method attributes)?
我想“读取”附加到 class 或方法的属性参数(例如 [MyAttribute("val1", "val2"]
),或者想取回特定 class 或方法。这似乎不适用于所有情况。
当我试图实现它时,即
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
我注意到我无法为所有 4 个案例实现它,我无法为案例 1. 和案例 4 实现它。我为案例 2. 和 3. 编写的代码工作正常(我删除了它因为您现在对所有 4 个案例都有 Tobias 的回答)。 SO 侧边栏显示了一些有趣的链接(“相关”:Link 1, Link 2, Link 3),但我仍然无法将缺失的部分放在一起。
考虑以下自定义属性:
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();
}
}
或者我可以像这样定义属性:
public string[] MyProperties { get; set; }
// allows any number of properties in constructor
public MyOwnAttribute(params object[] p)
{
MyProperties = p.Select(s => s.ToString()).ToArray();
}
但我不知道你如何实现这个:
问题 1: 如何访问附加到 class[=69= 的属性参数值列表]?
(来自属性的构造函数,就像为方法实现的一样)
示例:
var classAttribParamValues = MyOwnAttribute.GetClassAttributeValues(typeof(clsA));
string.Join(' ', classAttribParamValues.Select(s => s ?? "")).Dump();
问题 2: 如何访问附加到 方法 的属性的特性?
(类似于 class 的实现)
示例:
var methodInfo = MyOwnAttribute.GetMethodAttributes<clsA>(nameof(clsA.MyMethod2));
methodInfo.MyProperty1.Dump();
有没有人知道如何做到这一点?非常感谢。
编辑:
经过一些澄清后,我怀疑您想要的是:
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();
}
这些方法现在都是静态的,AttributeHelper 不再派生自 Attribute,因为无论如何您都必须提供属性类型作为方法的参数。作为第二个参数,只需提供您期望属性的 class。
我花了一些时间重新组织代码,因为它对我来说很难阅读。也许它对您来说也更容易阅读。
调用示例:
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.");
下面的旧答案:
我认为您想要实现的目标可以通过在 AttributeHelper 中使用 return 类型 string[]
的附加 protected abstract
方法来解决,这将使AttributeHelper也是抽象的,不过应该没问题。
您的派生属性将被迫实现这个新方法(如果它们本身不是抽象的)。实现必须 return 属性值的数组。
另一种方法可能是遍历属性类型的 PropertyInfos 并以这种方式读取属性。
我想“读取”附加到 class 或方法的属性参数(例如 [MyAttribute("val1", "val2"]
),或者想取回特定 class 或方法。这似乎不适用于所有情况。
当我试图实现它时,即
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 attributeMyOwnAttribute
, there areMyProperty1
andMyProperty2
defined. So if you apply it to[MyOwnAttribute("World", "2")]
public void MyMethod2() {...}
,
how can I read them (the constructor assigns"World"
toMyProperty1
and"2"
toMyProperty1
)?
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
我注意到我无法为所有 4 个案例实现它,我无法为案例 1. 和案例 4 实现它。我为案例 2. 和 3. 编写的代码工作正常(我删除了它因为您现在对所有 4 个案例都有 Tobias 的回答)。 SO 侧边栏显示了一些有趣的链接(“相关”:Link 1, Link 2, Link 3),但我仍然无法将缺失的部分放在一起。
考虑以下自定义属性:
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();
}
}
或者我可以像这样定义属性:
public string[] MyProperties { get; set; }
// allows any number of properties in constructor
public MyOwnAttribute(params object[] p)
{
MyProperties = p.Select(s => s.ToString()).ToArray();
}
但我不知道你如何实现这个:
问题 1: 如何访问附加到 class[=69= 的属性参数值列表]?
(来自属性的构造函数,就像为方法实现的一样)
示例:
var classAttribParamValues = MyOwnAttribute.GetClassAttributeValues(typeof(clsA));
string.Join(' ', classAttribParamValues.Select(s => s ?? "")).Dump();
问题 2: 如何访问附加到 方法 的属性的特性?
(类似于 class 的实现)
示例:
var methodInfo = MyOwnAttribute.GetMethodAttributes<clsA>(nameof(clsA.MyMethod2));
methodInfo.MyProperty1.Dump();
有没有人知道如何做到这一点?非常感谢。
编辑:
经过一些澄清后,我怀疑您想要的是:
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();
}
这些方法现在都是静态的,AttributeHelper 不再派生自 Attribute,因为无论如何您都必须提供属性类型作为方法的参数。作为第二个参数,只需提供您期望属性的 class。
我花了一些时间重新组织代码,因为它对我来说很难阅读。也许它对您来说也更容易阅读。
调用示例:
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.");
下面的旧答案:
我认为您想要实现的目标可以通过在 AttributeHelper 中使用 return 类型 string[]
的附加 protected abstract
方法来解决,这将使AttributeHelper也是抽象的,不过应该没问题。
您的派生属性将被迫实现这个新方法(如果它们本身不是抽象的)。实现必须 return 属性值的数组。
另一种方法可能是遍历属性类型的 PropertyInfos 并以这种方式读取属性。