-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
.NET core hosting: how to instantiate objects, call members functions ? #18174
Comments
@mjrousos Perhaps you can comment? |
@mjrousos I would be really helped by any comment, even just "that's not planned" or "that's not a good idea, look at X instead". |
Any news? I'd also be interested :) |
Sent an email to @mjrousos |
I believe .NET Core hosting APIs can only call static managed methods, but I haven't worked on hosting recently so it's possible things have changed. @AaronRobinsonMSFT, are you the right person to ask if this is still the case or if there are now ways to instantiate managed objects directly from .NET Core hosting APIs? As far as I know, the recommendation would be to have a static managed entry point that does the necessary object instantiation, calling of instance methods, etc. |
@mjrousos Yes. That recommendation is still correct. As @gabrieldevillers mentions there is the COM/ |
I updated my initial comment to mention CoreRT which might also be a possibility to call C# from C++ in a cross-platform way (I do not know what @MichalStrehovsky or @jkotas would think of this idea). Droping reflection could be an acceptable tradeoff for us given that we would write new code. |
@gabrieldevillers The problem isn't necessarily calling C# from C++, but rather interacting with an object in a "natural" (read OOP) manner that is troublesome. An example of consuming C# from native code is https://github.com/AaronRobinsonMSFT/DNNE or loading the CLR manually and getting a delegate - see https://github.com/dotnet/samples/tree/master/core/hosting/HostWithHostFxr/src. The ability to interact with objects in a "natural" way would require some kind of embedding API or building up an |
@AaronRobinsonMSFT Thanks for this answer, I was able to build & run your DNNE project. Then I tried to use GetIUnknownForObject() to get a intptr_t handle to a managed object that I would like to pass to the C side, as I am on Linux this failed (obviously) with "System.PlatformNotSupportedException: COM Interop is not supported on this platform." I also found this SO thread: https://stackoverflow.com/questions/32295586/save-reference-to-managed-object-in-unmanaged-memory which makes me question this strategy (even if we had COM on Linux). Do you see any way to build a solution on top of DNNE to pass to the unmanaged side a handle to a managed object on Linux ? I do not care about nice OO semantics for now. |
@gabrieldevillers Thanks for keeping this conversation going. It is something we are looking into working on in the next release but need more user feedback before making that decision. This conversation feeds into the planning calculus so please keep it going. As mentioned, the
class Foo
{
public int DoubleInt(int a)
{
return a * 2;
}
}
[UnmanagedCallersOnly]
public static IntPtr NewFoo()
{
return GCHandle.ToIntPtr(GCHandle.Alloc(new Foo()));
}
[UnmanagedCallersOnly]
public static void DeleteFoo(IntPtr fooRaw)
{
GCHandle.FromIntPtr(fooRaw).Free();
}
[UnmanagedCallersOnly]
public static int CallFooDoubleInt(IntPtr fooRaw, int a)
{
var foo = (Foo)GCHandle.FromIntPtr(fooRaw).Target;
return foo.DoubleInt(a);
} Notice that we have converted an OOP style into how it would be done if we wanted classes in C. The benefit of (1) is that all of the lifetime and much of the marshalling code can be generated and handled for you. The benefit of (2) is that if you have performance constraints or special marshalling requirements you have full control. Choosing one is based on product need and level of complexity that one would like to introduce into their project. |
Thanks for these explanations, they are very helpful. I will try to go with (2) and maybe do some benchmarks when I have time to see the impact of the pinning on the C# performance (but I suspect this will be very application-specific). Do you think that the pinning cost could be reduced by adding 1 level of indirection in C# made of small objects holding the reference to the "real" C# objects ? An pool of arbitrary size of these small objects could be created at the very beginning of the program and then be recycled as the "real" C# objects are deleted/created. This way the "real" C# objects would never be pinned and could be moved around in memory to protect the cache, only the "small objects" would be pinned and (supposedly) the performance cost would be lower as they would be tightly packed and at the "start" of the memory. |
There should be no pinning involved when passing GCHandles around. The code snippet above has a bug. The
The GCHandles are very similar to your pinned small object idea. They are small, never move around, and allocated in a different part of memory than regular objects to avoid impacting performance. |
I have edited @AaronRobinsonMSFT 's post to fix the bug. |
Thanks @jkotas So to be sure I understood: pinning is not needed in this case, but still useful in other cases like I/O to a C# buffer from C ? |
Right. |
This issue has been closed as part of the issue backlog grooming process outlined in #22351. That automated process may have closed some issues that should be addressed. If you think this is one of them, reopen it with a comment explaining why. Tag the |
The current documentation does not tell whether instantiating objects and calling member functions is impossible or just out of scope for this tutorial. I searched a lot online and found no more information on that.
This is something which is possible to do with Mono (using
mono_object_new
andmono_runtime_invoke
according to https://www.mono-project.com/docs/advanced/embedding/).Is this something that is not currently possible with .NET core ? Do you think this will be possible in the future, and when approximately would you expect it to be implemented ?
This feature is appealing because embedding C# is the best option I found to call C# from C++ in a cross-platform way:
Thanks in advance.
[Edited by gewarren to add document details]
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
The text was updated successfully, but these errors were encountered: