Pio*_*trK 13 c# reflection lambda
在 C# 中,我在给定的类(非静态)中定义了以下方法:
int MyMethod(ScriptEngine script, int a, int b) {
return a + b;
}
void MyMethod2(ScriptEngine script, string c) {
// do something with c
}
Run Code Online (Sandbox Code Playgroud)
我想创建包装 lambda / Action / Delegate / MethodInfo(所有这些都被脚本引擎接受),它会自动传递ScriptEngine
和this
从给定的预定义变量。
到目前为止,我已经尝试过:
// With overloads up to 16 template parameters
Action<T1> Wrap<T1>(Action<ScriptEngine, T1> func, ScriptEngine script) {
return (Action<T1>) ((t1) => func(script, t1));
}
Run Code Online (Sandbox Code Playgroud)
但是当调用 MyMethod2 时,我得到了The type arguments for method … cannot be inferred from the usage. Try specifying the type arguments explicitly
. 如果我明确指定模板参数,它就可以工作,但我想避免这样的规范。
有没有其他方法(不需要按照我的解决方案)我可以自动(或半自动)创建这样的包装器?
值得一提的是,有一个专用的抽象方法void RegisterAll(ScriptEngine script)
可以注册给定子类的所需成员。
这是我试图实现的一个例子:
class ScriptEngine { // Stub to have complete example, actual implementation is defined elsewhere
void RegisterApi(string name, MethodInfo methodInfo) { }
void RegisterApi(string name, Delegate delegateSelf) { }
}
class Api {
int MyMethod(ScriptEngine script, int a, int b) {
return a + b;
}
void MyMethod2(ScriptEngine script, string c) {
// do something with c
}
void RegisterAll(ScriptEngine script) {
// Is there any way to shorten this up (not providing MyMethod twice, not providing template arguments?)
script.RegisterApi(nameof(MyMethod), (Delegate)Wrap<string>(MyMethod, script));
}
}
Run Code Online (Sandbox Code Playgroud)
问题是如何改进这种RegisterApi
方法,以便它:
实际上还有另一种解决方案,不涉及发出新的表达式(在 iOS 上可能会失败!)
首先,让我们定义以下包装器:
private class Wrapper
{
public readonly object container;
public readonly MethodInfo method;
public readonly ScriptEngine engine;
public Wrapper(object container, MethodInfo method, ScriptEngine engine)
{
this.container = container;
this.method = method;
this.engine = engine;
}
public Action CreateAction()
{
return () => method.Invoke(container, new object[] { engine });
}
public Action<T1> CreateAction<T1>()
{
return (arg1) => method.Invoke(container, new object[] { engine, arg1 });
}
// etc
}
Run Code Online (Sandbox Code Playgroud)
现在你可以这样注册方法:
var type = typeof(Wrapper);
var instance = Activator.CreateInstance(type, new object[] { container, methodInfo, engine });
MethodInfo methodActual = null;
if (methodInfo.ReturnType == typeof(void))
{
var methods = type.GetMethods().Where(x => x.Name == "CreateAction");
foreach (var method in methods)
{
if (method.GetGenericArguments().Length == methodInfo.GetParameters().Length - 1)
{
methodActual = method.MakeGenericMethod(methodInfo.GetParameters().Skip(1).Select(x => x.ParameterType).ToArray());
}
}
}
var actionToRegister = methodActual.Invoke(instance, new object[0]);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
370 次 |
最近记录: |