[英]Lambda Generic Expression w/ Out Parameter
I am trying to use expressions w/ lambda delegates to obtain the name of the calling method but it is not formatting it properly. 我正在尝试使用带有lambda委托的表达式来获取调用方法的名称,但是它的格式不正确。
Here is what I have so far: Question is.. how do I get what I am to expect similar to foo.Method.Name for both lambda and regular methods? 到目前为止,这是我所拥有的:问题是..对于lambda和常规方法,我如何得到与foo.Method.Name类似的期望?
So far, I have tried with and without expressions.. and get the same results. 到目前为止,我尝试使用和不使用表达式..并获得相同的结果。
< HandleAddedDevice >b__2d <HandleAddedDevice> 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();
}
Here is a test driver I can show in a simple case of what I would expect. 这是一个测试驱动程序,我可以在一个简单的例子中展示我所期望的。 The 3x methods I need to support are: 我需要支持的3x方法是:
Func<T, TR>()
Func<T, TR>(T foo)
Func<T, TR>(out T foo)
Example: Lambda expressions are nameless. 示例: Lambda表达式是无名的。 It will show up something like < No Name>. 它将显示类似<No Name>的内容。
.Method.Name is correct, but since it is a sub-method of its Parent within the calling scope, it actually is registered on the stack, as follows: .Method.Name是正确的,但是由于它是调用范围内其Parent的子方法,因此它实际上是在堆栈上注册的,如下所示:
< HandleAddedDevice >b__2d <HandleAddedDevice> b__2d
I read here that I might need to make it an expression and then Expression.Compile() to convert it to an Action (or in my case Func)? 我在这里读到我可能需要使其成为一个表达式,然后使其成为Expression.Compile()以将其转换为Action(或者在我的情况下为Func)?
They said it may not be possible without a compiled expression here ... Maybe this will help you to explain to me where my code is a bit off in what I am trying to do. 他们说, 这里没有编译的表达式是不可能的。。。也许这可以帮助您向我解释我的代码在我尝试做的事情上有些偏离。
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...
I don't think it's possible. 我认为这是不可能的。 On Compiler Error CS1951 they write: 在编译器错误CS1951上,他们写道:
An expression tree just represents expressions as data structures. 表达式树仅将表达式表示为数据结构。 There is no way to represent specific memory locations as is required when you pass a parameter by reference. 当您通过引用传递参数时,无法代表所需的特定存储位置。
It looks like everything is fine except for how you are trying to extract the method name. 看起来一切正常,除了您尝试提取方法名称的方式。 Try this: 尝试这个:
public static string GetName<T>(Expression<T> field)
{
var callExpression = field.Body as MethodCallExpression;
return callExpression != null ? callExpression.Method.Name : string.Empty;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.