'Program+StringEventArgs' 类型的 ParameterExpression 不能用于 'System.EventArgs' 类型的委托参数
ParameterExpression of type 'Program+StringEventArgs' cannot be used for delegate parameter of type 'System.EventArgs'
我正在尝试使用反射将 MethodInfo
转换为 Func<T, TResult>
。到目前为止,我的代码在某些情况下似乎可以正常工作,但我无法使用派生自另一个参数类型的参数类型创建 Func
。我遗漏了一些东西,不幸的是我不知道如何从那里开始。我想某种 Expression.Convert()
是合适的,如果是的话,在哪里以及如何?
这是一个测试我想要实现的目标的简短程序。它可以复制粘贴到 https://dotnetfiddle.net/
并且应该正在编译。
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
var myObject = new MyClass();
var methodInfo = myObject.GetType().GetMethod("HelloThere");
var parameterType = methodInfo.GetParameters()[0].ParameterType;
var parameterExpression = Expression.Parameter(parameterType);
var callExpression = Expression.Call(Expression.Constant(myObject), methodInfo, parameterExpression);
var compiledFunction = Expression.Lambda<Func<EventArgs, string>>(callExpression, parameterExpression).Compile();
}
public class MyClass
{
public string HelloThere(StringEventArgs args)
{
return "General Kenobi";
}
}
public class StringEventArgs : EventArgs
{
public StringEventArgs(string aString)
{
Value = aString;
}
public string Value { get; set; }
}
}
但是,在运行时抛出以下错误:
Run-time exception (line 13): ParameterExpression of type 'Program+StringEventArgs' cannot be used for delegate parameter of type 'System.EventArgs'
当您使用
调用 Lambda 方法时
var compiledFunction = Expression.Lambda<Func<EventArgs, string>>(callExpression, parameterExpression).Compile();
您正在指定委托的类型是 Func。但是,只有当您的参数类型是 EventArgs 并且来自 HelloThere 的 return 类型是字符串时才会出现这种情况。从您收到的错误消息来看,这些不是实际类型;例如,错误指的是嵌套在程序类型中的类型 StringEventArgs。
此外,如果您知道参数类型是 EventArgs,那么动态获取 parameterType 值就没有意义了。
您可以尝试使用 Expression.Lambda 的不同重载。省略类型参数,只调用
var compiledFunction = Expression.Lambda(callExpression, new ParameterExpression[] { parameterExpression }).Compile();
这应该根据参数表达式的类型和调用表达式的类型动态构造 lambda 类型。
警告:我还没有真正尝试过。
你的代码有两个问题。
首先是您声明了类型为 StringEventArgs
的 ParameterExpression
,然后您试图将其用作 Func<EventArgs, string>
中的参数。那行不通:您需要使用 EventArgs
.
类型声明 ParameterExpression
第二个问题是您基本上是在尝试使用表达式构造此 C# 代码:
public string GeneratedMethod(EventArgs e)
{
return myClass.HelloThere(e);
}
那不会编译,因为你正在获取一个 EventArgs
类型的对象并试图将它传递给一个接受 StringEventArgs
.
的方法
在 C# 中,您可以添加一个强制转换,如果您实际上没有传递 StringEventArgs
:
,它将在运行时失败
public string GeneratedMethod(EventArgs e)
{
return myClass.HelloThere((StringEventArgs)e);
}
等价的表达式是Expression.Convert
。
把它们放在一起,你会得到:
var myObject = new MyClass();
var methodInfo = myObject.GetType().GetMethod("HelloThere");
var parameterExpression = Expression.Parameter(typeof(EventArgs));
var parameterType = methodInfo.GetParameters()[0].ParameterType;
var methodParameter = Expression.Convert(parameterExpression, parameterType);
var callExpression = Expression.Call(Expression.Constant(myObject), methodInfo, methodParameter);
var compiledFunction = Expression.Lambda<Func<EventArgs, string>>(callExpression, parameterExpression).Compile();
如果你传递的不是StringEventArgs
,这当然会在运行时失败并显示InvalidCastException
,即使compiledFunction
的签名说它可以接受任何EventArgs
.
的类型
我正在尝试使用反射将 MethodInfo
转换为 Func<T, TResult>
。到目前为止,我的代码在某些情况下似乎可以正常工作,但我无法使用派生自另一个参数类型的参数类型创建 Func
。我遗漏了一些东西,不幸的是我不知道如何从那里开始。我想某种 Expression.Convert()
是合适的,如果是的话,在哪里以及如何?
这是一个测试我想要实现的目标的简短程序。它可以复制粘贴到 https://dotnetfiddle.net/
并且应该正在编译。
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
var myObject = new MyClass();
var methodInfo = myObject.GetType().GetMethod("HelloThere");
var parameterType = methodInfo.GetParameters()[0].ParameterType;
var parameterExpression = Expression.Parameter(parameterType);
var callExpression = Expression.Call(Expression.Constant(myObject), methodInfo, parameterExpression);
var compiledFunction = Expression.Lambda<Func<EventArgs, string>>(callExpression, parameterExpression).Compile();
}
public class MyClass
{
public string HelloThere(StringEventArgs args)
{
return "General Kenobi";
}
}
public class StringEventArgs : EventArgs
{
public StringEventArgs(string aString)
{
Value = aString;
}
public string Value { get; set; }
}
}
但是,在运行时抛出以下错误:
Run-time exception (line 13): ParameterExpression of type 'Program+StringEventArgs' cannot be used for delegate parameter of type 'System.EventArgs'
当您使用
调用 Lambda 方法时var compiledFunction = Expression.Lambda<Func<EventArgs, string>>(callExpression, parameterExpression).Compile();
您正在指定委托的类型是 Func
此外,如果您知道参数类型是 EventArgs,那么动态获取 parameterType 值就没有意义了。
您可以尝试使用 Expression.Lambda 的不同重载。省略类型参数,只调用
var compiledFunction = Expression.Lambda(callExpression, new ParameterExpression[] { parameterExpression }).Compile();
这应该根据参数表达式的类型和调用表达式的类型动态构造 lambda 类型。
警告:我还没有真正尝试过。
你的代码有两个问题。
首先是您声明了类型为 StringEventArgs
的 ParameterExpression
,然后您试图将其用作 Func<EventArgs, string>
中的参数。那行不通:您需要使用 EventArgs
.
ParameterExpression
第二个问题是您基本上是在尝试使用表达式构造此 C# 代码:
public string GeneratedMethod(EventArgs e)
{
return myClass.HelloThere(e);
}
那不会编译,因为你正在获取一个 EventArgs
类型的对象并试图将它传递给一个接受 StringEventArgs
.
在 C# 中,您可以添加一个强制转换,如果您实际上没有传递 StringEventArgs
:
public string GeneratedMethod(EventArgs e)
{
return myClass.HelloThere((StringEventArgs)e);
}
等价的表达式是Expression.Convert
。
把它们放在一起,你会得到:
var myObject = new MyClass();
var methodInfo = myObject.GetType().GetMethod("HelloThere");
var parameterExpression = Expression.Parameter(typeof(EventArgs));
var parameterType = methodInfo.GetParameters()[0].ParameterType;
var methodParameter = Expression.Convert(parameterExpression, parameterType);
var callExpression = Expression.Call(Expression.Constant(myObject), methodInfo, methodParameter);
var compiledFunction = Expression.Lambda<Func<EventArgs, string>>(callExpression, parameterExpression).Compile();
如果你传递的不是StringEventArgs
,这当然会在运行时失败并显示InvalidCastException
,即使compiledFunction
的签名说它可以接受任何EventArgs
.