获取在操作中执行的方法的自定义属性
Get custom attribute of method executed in action
这是我的示例方法
[TestStep("Do something")]
private void DoSomething()
{
}
每个看起来像上面的方法的执行方式都需要记录方法参数:
private void LogStep(Action action)
{
string stepName = "[" + action.Method.Name + "] ";
var descr = Attribute.GetCustomAttribute(action.Method, typeof(TestStepAttribute)) as TestStepAttribute;
if (descr == null)
{
this.TestLog.AddWarningMessage(
(action.Method.DeclaringType == null ? string.Empty : action.Method.DeclaringType.FullName + ".") + action.Method.Name
+ ": missing description");
return;
}
stepName += descr.Description;
this.TestLog.EndGroup();
this.TestLog.BeginGroup(stepName);
}
这里我遇到了一个问题。像
一样执行 LogStep
LogStep(DoSomething)
完美运行,但是当我使用 lambda 表达式执行它时
LogStep(() => DoSomething())
告诉我Action
里面没有TestStepAttribute
类型的属性。
乍一看它似乎与 How do I get the custom attributes of a method from Action<T>? 相似,但在我的情况下,我既不能将 Action
的类型更改为 Expression<Action>
,也不知道方法名称。
任何建议都会有所帮助。
works perfectly, but when I execute it using lambda expression
LogStep(() => DoSomething()) It tells me that there are no attributes
of type TestStepAttribute in that Action.
当然不会找到任何属性,因为您传递的是 lambda 表达式,它基本上是一个方法,在该方法中您传递了方法 DoSomething() 并在 lambda 表达式上完成了检查。
Lambda 表达式只是另一种方法。当你查看 action.Method
时,这就是你得到的方法(action.Target
将包含一个闭包,如果有的话)。
最后,你只有:
void SomeAnonymousMethod()
{
DoSomething();
}
要获取实际调用的方法,您必须先反编译匿名方法。当然,您可能正在使用 lambda 语法传递参数,同时仍在使用无参数操作,这会变得更加疯狂:
class SomeClosure
{
string argument1;
int argument2;
void AnonymousMethod()
{
var data = GetSomeData(argument2);
DoSomething(data, argument1);
}
}
你甚至如何告诉 DoSomething
是你需要的元数据的方法?
无法使用 lambda 表达式解决此问题。幸运的是,看起来您实际上并不需要它,因为您从不调用参数。不使用Action
,只需要使用Delegate
,你可以直接传递任何你需要的方法:
void DoSomething(string something, string otherThing)
{
... // Not important
}
void LogStep(Delegate someDelegate)
{
... // Exactly as before
}
LogStep((Action<string, string>)DoSomething);
遗憾的是,您必须在调用时手动强制转换,否则编译器会报错;不过,您可以为 LogStep
方法本身保留相同的签名。或者,您可以使用简单的 T4 模板创建 LogStep
方法的多个重载,这样您就可以避免在手写代码中进行显式转换。
当您使用 lambda 表达式执行它时,lambda 表达式本身就是方法。碰巧在它的主体中有一个方法调用,但那里可能还有其他东西(比如 new object()
)。访问此内部方法的属性的唯一方法是将 lambda 表达式作为 Expression
传递并分析该表达式。
为了处理这两种情况,您需要 LogStep
的两个重载。但是,您不能同时将 LogStep(Action)
和 LogStep(Expression<Action>)
作为重载,因为调用会产生歧义。但如果其中之一是 LogStep(Delegate)
.
private void LogStep(Delegate action)
{
var attr = (TestStepAttribute)Attribute
.GetCustomAttribute(action.Method, typeof(TestStepAttribute));
Console.WriteLine("LogStep(Delegate action): " + attr?.Description);
}
private void LogStep(Expression<Action> actionExpr)
{
string descr = null;
var methodCall = actionExpr.Body as MethodCallExpression;
if (methodCall != null) {
var attribs = methodCall.Method.GetCustomAttributes(typeof(TestStepAttribute), true);
if (attribs.Length > 0) {
descr = ((TestStepAttribute)attribs[0]).Description;
}
}
Console.WriteLine("LogStep(Expression<Action> actionExpr): " + descr);
}
测试:
LogStep(new Action(DoSomething)); // new Action() Is required here. Calls first overlaod.
LogStep(() => DoSomething()); // Calls second overload.
LogStep(() => new object()); // Calls second overload.
请注意,您可以编译和执行 lambda 表达式,以防您需要执行该方法。
这是我的示例方法
[TestStep("Do something")]
private void DoSomething()
{
}
每个看起来像上面的方法的执行方式都需要记录方法参数:
private void LogStep(Action action)
{
string stepName = "[" + action.Method.Name + "] ";
var descr = Attribute.GetCustomAttribute(action.Method, typeof(TestStepAttribute)) as TestStepAttribute;
if (descr == null)
{
this.TestLog.AddWarningMessage(
(action.Method.DeclaringType == null ? string.Empty : action.Method.DeclaringType.FullName + ".") + action.Method.Name
+ ": missing description");
return;
}
stepName += descr.Description;
this.TestLog.EndGroup();
this.TestLog.BeginGroup(stepName);
}
这里我遇到了一个问题。像
一样执行 LogStepLogStep(DoSomething)
完美运行,但是当我使用 lambda 表达式执行它时
LogStep(() => DoSomething())
告诉我Action
里面没有TestStepAttribute
类型的属性。
乍一看它似乎与 How do I get the custom attributes of a method from Action<T>? 相似,但在我的情况下,我既不能将 Action
的类型更改为 Expression<Action>
,也不知道方法名称。
任何建议都会有所帮助。
works perfectly, but when I execute it using lambda expression
LogStep(() => DoSomething()) It tells me that there are no attributes of type TestStepAttribute in that Action.
当然不会找到任何属性,因为您传递的是 lambda 表达式,它基本上是一个方法,在该方法中您传递了方法 DoSomething() 并在 lambda 表达式上完成了检查。
Lambda 表达式只是另一种方法。当你查看 action.Method
时,这就是你得到的方法(action.Target
将包含一个闭包,如果有的话)。
最后,你只有:
void SomeAnonymousMethod()
{
DoSomething();
}
要获取实际调用的方法,您必须先反编译匿名方法。当然,您可能正在使用 lambda 语法传递参数,同时仍在使用无参数操作,这会变得更加疯狂:
class SomeClosure
{
string argument1;
int argument2;
void AnonymousMethod()
{
var data = GetSomeData(argument2);
DoSomething(data, argument1);
}
}
你甚至如何告诉 DoSomething
是你需要的元数据的方法?
无法使用 lambda 表达式解决此问题。幸运的是,看起来您实际上并不需要它,因为您从不调用参数。不使用Action
,只需要使用Delegate
,你可以直接传递任何你需要的方法:
void DoSomething(string something, string otherThing)
{
... // Not important
}
void LogStep(Delegate someDelegate)
{
... // Exactly as before
}
LogStep((Action<string, string>)DoSomething);
遗憾的是,您必须在调用时手动强制转换,否则编译器会报错;不过,您可以为 LogStep
方法本身保留相同的签名。或者,您可以使用简单的 T4 模板创建 LogStep
方法的多个重载,这样您就可以避免在手写代码中进行显式转换。
当您使用 lambda 表达式执行它时,lambda 表达式本身就是方法。碰巧在它的主体中有一个方法调用,但那里可能还有其他东西(比如 new object()
)。访问此内部方法的属性的唯一方法是将 lambda 表达式作为 Expression
传递并分析该表达式。
为了处理这两种情况,您需要 LogStep
的两个重载。但是,您不能同时将 LogStep(Action)
和 LogStep(Expression<Action>)
作为重载,因为调用会产生歧义。但如果其中之一是 LogStep(Delegate)
.
private void LogStep(Delegate action)
{
var attr = (TestStepAttribute)Attribute
.GetCustomAttribute(action.Method, typeof(TestStepAttribute));
Console.WriteLine("LogStep(Delegate action): " + attr?.Description);
}
private void LogStep(Expression<Action> actionExpr)
{
string descr = null;
var methodCall = actionExpr.Body as MethodCallExpression;
if (methodCall != null) {
var attribs = methodCall.Method.GetCustomAttributes(typeof(TestStepAttribute), true);
if (attribs.Length > 0) {
descr = ((TestStepAttribute)attribs[0]).Description;
}
}
Console.WriteLine("LogStep(Expression<Action> actionExpr): " + descr);
}
测试:
LogStep(new Action(DoSomething)); // new Action() Is required here. Calls first overlaod.
LogStep(() => DoSomething()); // Calls second overload.
LogStep(() => new object()); // Calls second overload.
请注意,您可以编译和执行 lambda 表达式,以防您需要执行该方法。