Подтвердить что ты не робот

Смешивание С# с помощью Objective-C

Я хотел бы использовать большую часть кода С# в качестве библиотеки для приложения Objective-C (Cocoa).

Я обнаружил проект MonoMac, который обертывает код Cocoa, но я предпочел бы иметь стандартное приложение Cocoa, написанное в Objective-C, которое может вызывать завернутый код С# (иначе).

В Windows я использую проект С++/CLI, который обертывает .NET-код и экспортирует простой старый интерфейс C для приложений на C/С++.

Есть ли простой способ достичь этого?

4b9b3361

Ответ 1

В Mac OS, очевидно, нет такого языка, как С++/CLI. В Windows С++/CLI фактически компилируется как управляемый код, запущенный CLR, который запускает собственный код; так как на Mac OS Mono не интегрирована в систему, это скорее наоборот. Ваше приложение является родным и может содержать управляемый код.

Mono предоставляет функции для размещения виртуальной машины CLR внутри процесса. Поскольку классы CLR не подвергаются прямому воздействию вашего C-кода, вы сможете вызывать методы объектов посредством отраженных вызовов.

Существует документация о том, как внедрить Mono в приложение на официальном сайте. Поскольку вы не заинтересованы в запуске .NET-программ напрямую, лучше прочитать "Вызов методов в CIL Universe" . В Mac OS вам нужно привязать к структуре Mono из вашей папки /Library/Frameworks вместо использования pkg-config.

Это действительно не должно заменять фактическое чтение вышеуказанного документа, но следующее можно рассматривать как руководство относительно того, чего ожидать:

#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 "Namespace.Class..ctor()")
mono_runtime_object_init(object);

// get a method handle to whatever you like
const char* descAsString = "Your.NameSpace.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, который обеспечивает привязки .NET к большой части API-интерфейсов, которые вы можете использовать в приложении Mac (Cocoa, CoreImage, CoreAnimation и т.д.) и означает создание собственных привязок.

Ответ 2

Если вы делаете это на Mac, то да, это возможно. На iOS не так много.

На Mac, если вы можете создать приложение CLI в MonoMac, вы можете вызвать свое приложение CLI из своего приложения Objective-C, используя NSTask. NSTask позволяет вам легко запустить инструмент командной строки, а затем захватить его вывод и взаимодействовать с ним. Чтобы сделать это, вы бы сделали что-то вроде:

NSArray *args = [NSArray arrayWithObjects:@"-arg1", @"-arg2", nil];
NSTask *foo = [[NSTask alloc] init];
[foo setLaunchPath:@"/usr/bin/foo"];
[foo setArguments:args];

NSPipe *pipe = [NSPipe pipe];
[foo setStandardOutput:pipe];

NSFileHandle *output = [pipe fileHandleForReading];

[foo launch];

NSData *data = [output readDataToEndOfFile];

NSString *outputStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"Got stuff: %@", outputStr);

Как правило, так, как вы хотите это сделать, вы включаете приложение CLI внутри своего пакета приложений. Затем вы можете получить путь к CLI-приложению, используя NSBundles -pathForResource: ofType: method.

iOS не включает API NSTask, поэтому это невозможно. Я слышал о том, как некоторые люди используют MonoTouch, чтобы сделать приложения для iOS с помощью С#, но, как вы сказали, я думаю, что вам лучше всего придерживаться Objective-C для большей части вашего приложения, если это возможно. Использование CLI-приложения, как вы описываете, определенно является опцией на Mac и может быть особенно полезно, когда у вас есть код, который уже написан и протестирован и работает, что вы просто хотите "обернуть" графическим интерфейсом Cocoa.

Итак, NSTask - это один из способов сделать это, используя внешний исполняемый файл CLI, завернутый в ваш пакет приложений. С другой стороны, вам может быть интересно, можете ли вы связать свой код С# непосредственно с Objective-C?

Ну, Objective-C является надмножеством C, и как таковой он обладает всеми возможностями C. Кроме того, если вы используете Objective-C ++, он также обладает всеми возможностями С++. Итак, ЕСЛИ вы можете получить MonoMac для создания статической библиотеки C или С++, тогда да, вы могли бы просто связать свою статическую библиотеку с кодом Objective-C Cocoa, и она будет работать. Я не могу сказать вам, как сделать библиотеку из MonoMac, но связать ее - это просто добавить ее в ваши связанные библиотеки в настройках сборки в Xcode.

EDIT: Я не знаком с С++/CLI как языком, и я неверно истолковал значение С++/CLI как "С++ Command Line Interface app". Тем не менее... описанные мной методы по-прежнему применяются как возможные методы для выполнения того, что вы хотите сделать, но НЕ используют интерфейс С++/CLI, как вы можете в Windows.