Search code examples
xamarinxamarin.mac

How to call base/super class implementation (super.SomeMethod()) when implementing informal protocol using the ExportAttribute


I have the following reference swift code and I'm trying to implement the same thing in xamain.mac.

class MyTableView : NSTableView {
    override func cancelOperation(_ sender: Any?) {
        // some custom processing goes here
        super.cancelOperation(sender)        
        // another part of custom processing goes here
    }
}

The problem is that in the C# the NSTableView does not implement cancelOperation:, so there is nothing to override.

I was able to handle the message with the direct export inside my NSTableView subclass:

[Export("cancelOperation:")]
private void CancelOperation(NSObject? sender)
{
    // some custom processing
    System.Diagnostics.Debug.WriteLine("Custom processing");
    
    //won't compile
    //base.CancelOperation(sender);
    
    //crashes the app
    objc_msgSendSuper(this.SuperHandle, Selector.GetHandle("cancelOperation:"),
                                        sender?.Handle ?? NativeHandle.Zero);
    
    //another part of custom processing
    System.Diagnostics.Debug.WriteLine("another part of custom processing");
}

[DllImport ("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
private static extern void objc_msgSendSuper(NativeHandle superReceiver, 
                                             NativeHandle selector,
                                             NativeHandle value);

And then the problem is that I can't call base/super implementation as a Swift code does. I can't just write base.CancelOperation(sender) because of this is not an overridden member, but a direct export.

As a workaround I tried to use objc_msgSendSuper, but this crashes the application (most likely because I'm doing it wrong).

So, the question is - how to implement the custom handler for the cancelOperation: (or other member of informal protocol) and call the base/super implementation from such a handler.

Test project which demonstrates the problem may be downloaded here. Just enter something into the second column of the table then press Esc. This will cause a crash due to the objc_msgSendSuper inside the MyNSTableView.CancelOperation handler.


Solution

  • I finally got it to work. The approach from the question was correct, and the problem was in the stupid mistake in the objc_msgSendSuper declaration - the functinon name is correct, but EntryPoint is wrong! The correct EntryPoint is objc_msgSendSuper.

    So after replacing declaration with the following all works as expected:

    [DllImport ("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSendSuper")]
    private static extern void objc_msgSendSuper(NativeHandle superReceiver, NativeHandle selector, NativeHandle value);