Question

I'm writing a wrapper around some C code, and I can't quite figure out how to write this bit without being able to use the ref keyword in a lambda.

The unmanaged function wrappers look like this:

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

But I don't want to use SDL_Event directly (it's a complicated struct), so I've wrapped it in my own class, Event. However, C is expecting a pointer to an SDL_Event not an Event so I have to write some more code to wrap it all up:

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

This basically takes the SDL_Event that I'm given and converts it into my Event class. However, I can't use the ref keyword inside a lambda, but I'm not sure how to get around it.

I could define a regular helper method instead of using a lambda, but I need to use the local filter variable inside of it, and I don't know how to get that into the function without changing the signature (then it wouldn't match SDL_EventFilter).

In JavaScript, PHP, or Python I could construct a callable object, make filter a member variable, and then use the object as the callback. I'm not sure if there's a similar concept in C#, is there?

Was it helpful?

Solution

When using the ref keyword, the type must also be given. Like this:

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

The parameter list of a lambda is like the parameter list of an ordinary named method. The types can be left out in a lambda, however, but only when no parameters have modifyers such as ref, out, params.

OTHER TIPS

Yes you can't do it since Lambda actually captures the variable in CompilerGenerated class and reuses it.

We can make use of ref keyword while passing to a method, but still if you capture the parameter to someother variable It wont behave as you expect.

So easy workaround will be create a method and use instead of lambda.

Something like this (untested):

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top