如何解决无法在lambda中使用refs的问题?

时间:2013-08-05 22:08:58

标签: c# interop ref callable

我正在编写一些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#中是否有类似的概念,是吗?

3 个答案:

答案 0 :(得分:3)

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

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

lambda的参数列表类似于普通命名方法的参数列表。但是,类型可以在lambda中省略,但仅当没有参数包含refoutparams等修改器时。

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