如何解决不能在lambda中使用refs的问题

本文关键字:refs 问题 何解 决不能 lambda | 更新日期: 2023-09-27 18:26:28

我正在为一些C代码编写一个包装器,如果不能在lambda中使用ref关键字,我就不太清楚如何编写这一位。

非托管函数包装器如下所示:

[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关键字,但我不知道如何绕过它

我可以定义一个常规的helper方法,而不是使用lambda,但我需要在其中使用本地filter变量,而且我不知道如何在不更改签名的情况下将其输入函数中(这样它就不匹配SDL_EventFilter)。

在JavaScript、PHP或Python中,我可以构造一个可调用的对象,使filter成为成员变量,然后使用该对象作为回调。我不确定C#中是否有类似的概念,是吗?

如何解决不能在lambda中使用refs的问题

使用ref关键字时,还必须给定类型。像这样:

(ref object data, ref SDL_Event e) => { ... }

lambda的参数列表类似于普通命名方法的参数列表。但是,在lambda中可以省略这些类型,但前提是没有参数具有修饰符(如refoutparams)。

是的,您不能这样做,因为Lambda实际上捕获了CompilerGenerated类中的变量并重用它。

我们可以在传递给方法时使用ref关键字,但如果您将参数捕获到其他变量It wont behave as you expect,则仍然可以。

因此,简单的解决方法是创建一个方法并使用,而不是lambda。

类似的东西(未经测试):

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);
}