问题描述
我想使用更大的 C# 代码作为 Objective-C (Cocoa) 应用程序的库.
I would like to use larger body of C# code as a library for Objective-C (Cocoa) application.
我发现了封装 Cocoa 代码的 MonoMac 项目,但我宁愿拥有用 Objective-C 编写的标准 Cocoa 应用程序,它可以调用封装的 C# 代码(其他方式).
I discovered MonoMac project which wraps Cocoa code, but I would rather have standard Cocoa application written in Objective-C, which can call wrapped C# code (other way around).
在 Windows 上,我习惯于制作 C++/CLI 项目,该项目包装 .NET 代码并为基于 C/C++ 的应用程序导出普通的旧 C 接口.
On Windows I am used to make C++/CLI project which wraps .NET code and exports plain old C interface for C/C++ based apps.
有什么简单的方法可以实现吗?
Is there some simple way to achieve this?
推荐答案
显然,Mac OS 上没有 C++/CLI 这样的语言.在 Windows 上,C++/CLI 实际上编译为由 CLR 运行的托管代码,即运行本机代码;因为在 Mac OS Mono 上并没有集成到系统中,所以相反.您的应用是本机应用,它可以托管托管代码.
There is, obviously, no such language as C++/CLI on Mac OS. On Windows, C++/CLI actually compiles as managed code ran by the CLR, that runs native code; since on Mac OS Mono isn't integrated to the system, it's rather the other way around. Your app is native, and it can host managed code.
Mono 公开了在进程内托管 CLR 虚拟机的函数.由于 CLR 类不直接暴露给您的 C 代码,因此您将能够通过类似反射的调用来调用对象的方法.
Mono exposes functions to host a CLR virtual machine inside a process. Since CLR classes aren't directly exposed to your C code, you'll be able to call methods of objects through reflection-like calls.
官方网站上有关于如何将Mono嵌入应用程序的文档.由于您对直接运行 .NET 程序不感兴趣,您应该阅读 在 CIL 世界中调用方法" 部分.在 Mac OS 上,您需要从 /Library/Frameworks
文件夹链接 Mono 框架,而不是使用 pkg-config
.
There is documentation on how to embed Mono into an application on the official site. Since you're not interested in running .NET programs directly, you should rather read the "Invoking Methods in the CIL Universe" section. On Mac OS, you'll want to link against the Mono framework from your /Library/Frameworks
folder, instead of using pkg-config
.
这确实不应该取代对上述文档的实际阅读,但可以将以下内容视为预期内容的指南:
This really shouldn't replace an actual reading of the above document, but the following can be seen as a guide as to what to expect:
#include <glib/glib.h>
#include <mono/jit/jit.h>
#include <mono-metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
// create an app domain
// http://en.wikipedia.org/wiki/Application_Domain
MonoDomain* domain = mono_jit_init("Domain");
// mandatory Cocoa call to show that Mono and ObjC work together
NSBundle* mainBundle = [NSBundle mainBundle];
NSString* dll = [mainBundle pathForResource:@"your-dll" ofType:@"dll"];
// load the referenced assembly in our domain
MonoAssembly* assembly = mono_domain_assembly_open(domain, [dll UTF8String]);
MonoImage* image = mono_assembly_get_image(assembly);
// find the class we want to wrap and create an uninitialized instance
MonoClass* classHandle = mono_class_from_name(image, "Name.Space", "YourClass");
MonoObject* object = mono_object_new(domain, classHandle);
// this calls the default, argument-less ctor
// for more complex constructors, you need to find the method handle and call it
// (helpful hint: constructors are internally called ".ctor", so the description
// string will look like "Name.Space.Class:.ctor()")
mono_runtime_object_init(object);
// get a method handle to whatever you like
const char* descAsString = "Name.Space.YourClass:YourMethod()";
MonoMethodDesc* description = mono_method_desc_new(descAsString);
MonoMethod* method = mono_method_desc_search_in_class(description, classHandle);
// call it
void* args[0];
mono_runtime_invoke(method, object, args, NULL);
// when you're done, shutdown the runtime by destroying the app domain
mono_jit_cleanup(domain);
如果你觉得这不是很吸引人,你可能想反过来,就像你提到的那样,看看 MonoMac,它为您可能希望在 Mac 应用程序(Cocoa、CoreImage、CoreAnimation 等)中使用的大部分 API 提供 .NET 绑定,并意味着创建自己的绑定.
If you don't find this very appealing, you may want to go the other way around, as you mentioned, and look into MonoMac, which provides .NET bindings to a large portion of the APIs you may want to use in a Mac application (Cocoa, CoreImage, CoreAnimation, etc) and means to create your own bindings.
这篇关于将 C# 与 Objective-C 混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!