我正在编写一些C代码的包装器,我无法弄清楚如何在不能使用ref
keyword in a lambda的情况下编写这个位。
非托管函数包装器看起来像这样:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int SDL_EventFilter(ref object userData, ref SDL_Event @event);
[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_AddEventWatch")]
internal static extern void SDL_AddEventWatch(SDL_EventFilter filter, ref object userData);
但我不想直接使用SDL_Event
(这是一个复杂的结构),所以我把它包装在我自己的类Event
中。但是,C期望指向SDL_Event
而不是Event
的指针,所以我必须编写更多代码来包装它们:
public delegate void EventFilter(object userData, Event @event);
public static void AddEventWatch(EventFilter filter, object userData)
{
SDL_AddEventWatch((ref data, ref e) => // <-- can't do this
{
filter(data, new Event(ref e));
return 0;
}, ref userData);
}
这基本上取了我给出的SDL_Event
并将其转换为我的Event
类。但是,我不能在lambda中使用ref
关键字,但我不确定如何绕过它。
我可以定义一个常规的辅助方法,而不是使用lambda,但我需要在其中使用本地filter
变量,我不知道如何在不改变签名的情况下将其转换为函数(然后它不匹配SDL_EventFilter
)。
在JavaScript,PHP或Python中,我可以构造一个可调用对象,使filter
成为一个成员变量,然后使用该对象作为回调。我不确定C#中是否有类似的概念,是吗?
答案 0 :(得分:3)
使用ref
关键字时,还必须提供类型。像这样:
(ref object data, ref SDL_Event e) => { ... }
lambda的参数列表类似于普通命名方法的参数列表。但是,类型可以在lambda中省略,但仅当没有参数包含ref
,out
,params
等修改器时。
答案 1 :(得分:2)
是的,你不能这样做,因为Lambda
实际捕获CompilerGenerated
类中的变量并重用它。
我们可以在传递给方法时使用ref
关键字,但是如果将参数捕获到另一个变量It wont behave as you expect
仍然可以。
如此简单的解决方法是创建一个方法并使用而不是lambda。
答案 2 :(得分:1)
像这样(未经测试):
class Capture
{
private readonly EventFilter filter;
public Capture(EventFilter filter)
{
this.filter = filter;
}
public int Method(ref object userData, ref SDL_Event @event)
{
this.filter(userData, new Event(ref event));
return 0;
}
}
public static void AddEventWatch(EventFilter filter, object userData)
{
var capture = new Capture(filter);
SDL_AddEventWatch(capture.Method, ref userData);
}