You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
partialclassMyObject{class__RegistrarHelper_{[UnmanagedCallersOnly ("__MyObject_DoSomething__")]staticvoidDoSomething(IntPtrhandle,IntPtrselector,IntPtrarg1){// Runtime.GetNSObject:// https://github.com/xamarin/xamarin-macios/blob/3dd412daa6b5522029014b0be298f27d751c5f45/src/ObjCRuntime/Runtime.cs#L1516-L1519// basically something like this:// if we already have a managed instance for the handle 'handle', return that// otherwise find the constructor that takes an IntPtr (using reflection), and call that constructorvararg1Obj= Runtime.GetNSObject();
MyObject.DoSomething(arg1Obj);}}}
This is in some ways very similar to Filip's INativeObject/Selector case from above, except a bit more complex, because Runtime.GetNSObject will look up the actual runtime type of the Objective-C handle, find the closest matching C# type, and create an instance of that type. This might very well be a subclass of the type the caller expects (and this is why we can't just do a new NSString (handle) in the generated code).
Potential solution: we already generate a table to map Objective-C class -> managed type (which we use to find the closest matching C# type for a given Objective-C classr), we could add the token for the IntPtr ctor to table, so that when we find a managed type, we'll find the ctor to call too (or maybe even generate code to call the ctor directly, because calling a method given a token in C# is rather obnoxious)
The text was updated successfully, but these errors were encountered:
I experimented with a C#-only solution that could potentially work with roslyn source generators in the future. I came up with a PoC which isn't very different from the current solution that uses reflection but uses the recently introduced zero-overhead unsafe accessors and a "trick" to make it impossible for NativeAOT to generate extra metadata:
partialclassCustomClass:NSObject{privateint_x;[Export ("initWithX:")]publicCustomClass(intx)=>_x=x;}// generated:partialclassCustomClass{staticclass__Registrar_Callbacks__{[UnmanagedCallersOnly (EntryPoint ="_callback_CustomClass__ctor")]privatestatic IntPtr callback_CustomClass__ctor(IntPtrhandle,intx){varobj= NSObject.CreateNSObject<CustomClass>(handle);
ctor (obj, x);return Runtime.AllocGCHandle(obj);[UnsafeAccessor(UnsafeAccessorKind.Method, Name =".ctor")]externstaticvoidctor(CustomClass@this,intx);}}}// xamarin runtime:classNSObject{[UnconditionalSuppressMessage("ReflectionAnalysis","IL2087:UnrecognizedReflectionPattern", MessageId ="We make sure there are hard references to the type's constructor(s) through the UnsafeAccessor "+"and ILC will find it and include it.")]publicstatic T CreateNSObject<T>(IntPtrhandle)whereT:NSObject{varobj=(T)RuntimeHelpers.GetUninitializedObject(typeof(T));// ILC won't generate extra metadata since we don't use typeof(CustomClass) directlyref IntPtr _handle=ref GetHandle(obj);_handle=handle;returnobj;}[UnsafeAccessor(UnsafeAccessorKind.Field, Name ="_handle")]externstaticref IntPtr GetHandle(NSObject@this);}
…using reflection in the managed static registrar (#18519)
This PR adds lookup tables and factory methods for INativeObjects and
NSObjects. These generated methods allow us to create instances of these
objects without needing reflection.
Closes#18358.
Ref: last part of dotnet/runtime#86649 (comment)
When instantiating a managed NSObject instance (or subclass) for an existing Objective-C object
Say we have the following managed class:
In this case we do something like:
This is in some ways very similar to Filip's INativeObject/Selector case from above, except a bit more complex, because
Runtime.GetNSObject
will look up the actual runtime type of the Objective-Chandle
, find the closest matching C# type, and create an instance of that type. This might very well be a subclass of the type the caller expects (and this is why we can't just do anew NSString (handle)
in the generated code).Potential solution: we already generate a table to map Objective-C class -> managed type (which we use to find the closest matching C# type for a given Objective-C classr), we could add the token for the IntPtr ctor to table, so that when we find a managed type, we'll find the ctor to call too (or maybe even generate code to call the ctor directly, because calling a method given a token in C# is rather obnoxious)
The text was updated successfully, but these errors were encountered: