如何从Action获取方法的自定义属性 ?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从Action获取方法的自定义属性 ?相关的知识,希望对你有一定的参考价值。
如何从Action<T>
委托中获取方法的自定义属性?
例:
//simple custom attribute
public class StatusAttribute : Attribute
{
public string Message { get; set; } = string.Empty;
}
// an extension methodto wrap MethodInfo.GetCustomAttributes(Type, Bool) with
// generics for the custom Attribute type
public static class MethodInfoExtentions
{
public static IEnumerable<TAttribute> GetCustomAttributes<TAttribute>(this MethodInfo methodInfo, bool inherit) where TAttribute : Attribute
{
object[] attributeObjects = methodInfo.GetCustomAttributes(typeof(TAttribute), inherit);
return attributeObjects.Cast<TAttribute>();
}
}
// test class with a test method to implment the custom attribute
public class Foo
{
[Status(Message="I'm doing something")]
public void DoSomething()
{
// code would go here
}
}
// creates an action and attempts to get the attribute on the action
private void CallDoSomething()
{
Action<Foo> myAction = new Action<Foo>(m => m.DoSomething());
IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true);
// Status Attributes count = 0? Why?
}
我意识到我可以通过对Foo使用反射来做到这一点,但是对于我想要创建的东西,我必须使用Action<T>
。
问题是该行动并未直接指向Foo.DoSomething
。它指向编译器生成的表单方法:
private static void <>__a(Foo m)
{
m.DoSomething();
}
这里的一个选择是将其更改为Expression<Action<T>>
,然后您可以解剖表达式树并提取属性:
Expression<Action<Foo>> myAction = m => m.DoSomething();
var method = ((MethodCallExpression)myAction.Body).Method;
var statusAttributes = method.GetCustomAttributes<StatusAttribute>(true);
int count = statusAttributes.Count(); // = 1
问题是lambda m => m.DoSomething()
与DoSomething
不同。它是一个lambda表达式,它被编译成编译器生成的方法上的方法调用,可能使用编译器生成的类型(尽管可能不是后者,因为没有捕获的局部变量)。
从Action<Foo>
类型的实例(非静态)方法获取Foo
的一种非常详细的方法是:
var myAction = (Action<Foo>)Delegate.CreateDelegate(
typeof(Action<Foo>),
null, // treat method as static, even though it's not
typeof(Foo).GetMethod("DoSomething", BindingFlags.Instance | BindingFlags.Public)
);
显然,这远非理想,在你的情况下可能实际上毫无用处;但值得了解;)
更新:实际上,我刚刚想到你可以编写一个快速扩展方法,使你想要包装为静态方法的任何实例方法都很容易(并保持“正确”的MethodInfo
):
public static class ActionEx
{
public static Action<T> ToStaticMethod<T>(this Action action)
{
if (!(action.Target is T))
{
throw new ArgumentException("Blah blah blah.");
}
return (Action<T>)Delegate.CreateDelegate(
typeof(Action<T>),
null,
action.Method
);
}
}
这将允许您:
Action<Foo> myAction = new Action(new Foo().DoSomething).ToStaticMethod<Foo>();
不可否认,它不如m => m.DoSomething()
那么好;但它确实给你一个Action<T>
,其Method
属性实际上直接引用DoSomething
方法。
或者,你可以使用Action<T>
而不是Expression<Action<T>>
,并从中得到MethodInfo
。请注意,在这种情况下,语法看起来是一样的:
Action<Foo> myAction = m => m.DoSomething();
Expression<Action<Foo>> myExpression = m => m.DoSomething();
但这是一个棘手的主张,因为任意Expression<Action<T>>
不能保证像m => m.DoSomething()
一样简单。
以前的答案都没有(除了没有用户代码的@Marc Gravell♦)似乎可以编译:)
所以我建议我的:
private static void CallDoSomething()
{
var f = new Foo();
Action myAction = f.DoSomething;
IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true);
}
以上是关于如何从Action获取方法的自定义属性 ?的主要内容,如果未能解决你的问题,请参考以下文章
按名称初始化、设置和获取我的自定义对象属性的 Pythonic 方法是啥?