dotnet / dotnet/macios

[rfc] NativeObjectAttribute: The class attribute to generate INativeObjects classes

Open
#3,582 23 comments 5 reactions 1 assignee Claimed by @dalexsoto View on GitHub
enhancement iOS macOS request-for-comments
Dominant language
C#
Stars
2.9k
Forks
576
Avg merge
2d 13h
Merged PRs (30d)
96

Description

### Description

Currently we do not provide a mechanism in the generator to generate bindings for [Core Foundation objects](https://developer.apple.com/documentation/corefoundation/cftyperef?language=objc) or objects like [VTSession](https://developer.apple.com/documentation/videotoolbox/vtsession).

The idea is to teach the generator how to create the boilerplate code for this kind of objects and be used in conjunction of [`[ExternizerAttribute]`](https://github.com/xamarin/xamarin-macios/issues/3452) to simplify the binding process for this kind of objects.

Introducing `[NativeObject]`:

```csharp
[AttributeUsage (AttributeTargets.Interface, AllowMultiple = false)]
public class NativeObjectAttribute : Attribute {
public Visibility OwnsCtorVisibility { get; set; } = Visibility.Internal;
public NativeObjectAttribute () { }
public NativeObjectAttribute (Visibility ownsCtorVisibility) => OwnsCtorVisibility = ownsCtorVisibility;
}
```

This would be used as follows:

```csharp
[NativeObject]
interface NFoo {
}
```

This will instruct the generator to create a `partial` subclass of the following new abstract class named `NativeObject` that would live inside `ObjCRuntime` namespace:

```csharp
public abstract class NativeObject : INativeObject, IDisposable {

IntPtr handle;
public IntPtr Handle {
get => handle;
protected set => InitializeHandle (value);
}

protected NativeObject (IntPtr handle, bool owns)
{
Handle = handle;
if (!owns)
DangerousRetain ();
}

~NativeObject ()
{
Dispose (false);
}

public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}

protected virtual void Dispose (bool disposing)
{
if (Handle != IntPtr.Zero) {
DangerousRelease ();
handle = IntPtr.Zero;
}
}

protected virtual void DangerousRetain () => CFObject.CFRetain (Handle);
protected virtual void DangerousRelease () => CFObject.CFRelease (Handle);

protected virtual void InitializeHandle (IntPtr handle)
{
if (Handle == IntPtr.Zero && Class.ThrowOnInitFailure) {
throw new Exception ($"Could not initialize an instance of the type '{GetType ().FullName}': handle is null.\n" +
"It is possible to ignore this condition by setting ObjCRuntime.Class.ThrowOnInitFailure to false.");
}
this.handle = handle;
}
}
```

The generated code would look like this:

```csharp
public partial class NFoo : NativeObject {

internal NFoo (IntPtr handle, bool owns) : base (handle, owns)
{
}
}
```

Most of the time these objects have factory methods, this is the reason why the `.ctor (IntPtr,bool)` is `internal` and can be implemented either manually or by using the [`[ExternizerAttribute]`](https://github.com/xamarin/xamarin-macios/issues/3452).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.