【发布时间】:2013-06-22 07:17:34
【问题描述】:
我正在尝试使用带有 lambda 委托的表达式来获取调用方法的名称,但它的格式不正确。
这是我目前所拥有的:问题是.. 对于 lambda 和常规方法,我如何获得类似于 foo.Method.Name 的期望?
到目前为止,我已经尝试过使用和不使用表达式......并得到相同的结果。
b__2d
// **************************************************************************
public delegate TResult TimerDelegateOut <T, out TResult>(out T foo);
// **************************************************************************
public static string GetName<T>(this Expression<T> expression) {
var callExpression = expression.Body as MethodCallExpression;
return callExpression != null ? callExpression.Method.Name : string.Empty;
}
// **************************************************************************
public static Expression<TimerDelegateOut<T, TResult>> ToExpression<T, TResult>(this TimerDelegateOut<T, TResult> call) {
var p1 = Expression.Parameter(typeof(T).MakeByRefType(), "value");
MethodCallExpression methodCall = call.Target == null
? Expression.Call(call.Method, p1)
: Expression.Call(Expression.Constant(call.Target), call.Method, p1);
return Expression.Lambda<TimerDelegateOut<T, TResult>>(methodCall, p1);
}
// **************************************************************************
public static Expression<Func<TResult>> ToExpression<TResult>(this Func<TResult> call) {
MethodCallExpression methodCall = call.Target == null
? Expression.Call(call.Method)
: Expression.Call(Expression.Constant(call.Target), call.Method);
return Expression.Lambda<Func<TResult>>(methodCall);
}
// **************************************************************************
public static TResult TimeFunction<T, TResult>(TimerDelegateOut<T, TResult> foo, out T bar) {
try {
var result = foo.ToExpression().Compile().Invoke(out bar);
Console.WriteLine(foo.GetName()); // is OKAY
return result;
} catch (Exception) {
bar = default(T);
return default(TResult);
}
}
// **************************************************************************
public static TResult TimeFunction<TResult>(Func<TResult> foo) {
try {
var result = foo.ToExpression().Compile().Invoke();
Console.WriteLine(foo.GetName()); // <-- prints "foo" ??? Not correct.
return result;
} catch (Exception) {
bar = default(T);
return default(TResult);
}
}
-------------
Result GetCamera_HWInfo(out Cam_HWInfo obj)
{
obj = new Cam_HWInfo() { < fill container here > };
return Result.cmrOk;
}
//------------
private void HandleAddedDevice() {
...
Cam_HWInfo camHWInfo;
Result result = Watchdog.TimeFunction(GetCamera_HWInfo, out camHWInfo);
...
// Try this one.. I am also using.
var connect = new Func<bool>(delegate {
try {
// ...
} catch (Exception ex) {
return false;
}
return true;
});
result = Watchdog.TimeFunction(connect);
}
//------------
// Assume OEP
static void Main(string[] args)
{
HandleAddedDevice();
}
这是一个测试驱动程序,我可以在一个简单的案例中展示我所期望的。我需要支持的 3x 方法是:
Func<T, TR>()Func<T, TR>(T foo)Func<T, TR>(out T foo)
示例:
Lambda 表达式是无名的。它将显示类似
.Method.Name是正确的,但由于是其Parent在调用范围内的子方法,所以实际上是在栈上注册的,如下:
b__2d
我读到here 可能需要将其设为表达式,然后将 Expression.Compile() 转换为 Action(或者在我的情况下为 Func)?
他们说,如果没有编译表达式 here,这可能是不可能的...也许这会帮助您向我解释我的代码在我想做的事情中有些偏离的地方。
class Program {
public static class ReflectionUtility {
public static string GetPropertyName<T>(Expression<Func<T>> expression) {
MemberExpression body = (MemberExpression) expression.Body;
return body.Member.Name;
}
}
static void Main(string[] args) {
Func<int, bool> lambda = i => i < 5;
Func<int, bool> del = delegate(int i) { return i < 5; };
// Create similar expression #1.
Expression<Func<int, bool>> expr1 = i => i < 5;
// Compile the expression tree into executable code.
Func<int, bool> exprC1 = expr1.Compile();
// Invoke the method and print the output.
Console.WriteLine("lambda(4) = {0} : {1} ", lambda(4), lambda.Method.Name);
Console.WriteLine("del (4) = {0} : {1} ", del(4), del.Method.Name);
Console.WriteLine("expr1 (4) = {0} : {1} ", exprC1(4), exprC1.Method.Name);
Console.WriteLine(" = {0}", ReflectionUtility.GetPropertyName(() => lambda));
Console.WriteLine(" = {0}", ReflectionUtility.GetPropertyName(() => del));
Console.Write("Press any key to continue...");
Console.ReadKey();
}
输出
lambda(4) = True : <Main>b__0
del (4) = True : <Main>b__1
expr1 (4) = True : lambda_method
= lambda
= del
Press any key to continue...
【问题讨论】:
-
我要装满的容器。刷新页面..我更新了问题。如您所见,我将其跟踪到调用调用并引发异常的方法。似乎坚持在扩展 ToExpression 中......我可以尝试在那里捕捉一些东西,看看我是否得到更多信息,但这并不重要,因为我正在赶上它一帧。重点是使用 foo.GetName(); 获取 lambda / delegates inline 和普通方法的方法名称
-
如果您只是
return (out T t) => call(out t);而您的方法中没有其他内容ToExpression会发生什么? -
GetCamera_HWInfo(out obj) 被填写,这个方法以前一直有效。类似地,现有代码在没有表达式的情况下工作......并且只有委托作为 arg。但是,我将它们全部包装起来,因为我在某个地方读到过,最好有表达式并从中获取更多信息,而不仅仅是代表.. lambda
尤其如此。 '表达式树 lambda 不能包含 out 或 ref 参数' -
您好 Rohan,感谢您的回复。我不久前读过那个帖子。您可以看到我的代码有效,并在您的线程中完成了您想要完成的工作。我担心无法从所有包装代码中获取调用方法/lambda 的名称。
标签: c# generics lambda expression-trees out