Смешивание C # с Objective-C

#c# #objective-c #cocoa #mono

#c# #objective-c #cocoa #моно

Вопрос:

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

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

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

Есть ли какой-нибудь простой способ добиться этого?

Комментарии:

1. На самом деле это довольно интересный вопрос. Не знаю, каков ответ, но мне интересно посмотреть, что люди скажут по этому поводу.

2. … и именно поэтому у нас есть кнопка «Проголосовать».

Ответ №1:

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

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

На официальном сайте есть документация о том, как встроить Mono в приложение. Поскольку вы не заинтересованы в непосредственном запуске .NET-программ, вам лучше прочитать раздел «Вызов методов во вселенной CIL». В Mac OS вам захочется создать ссылку на Mono framework из вашей /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 "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, который предоставляет привязки .NET к значительной части API, которые вы можете захотеть использовать в приложении Mac (Cocoa, CoreImage, CoreAnimation и т.д.) И средства для создания ваших собственных привязок.

Комментарии:

1. Спасибо. Это кажется возможным способом. Но это не так просто : (

2. @Filip Kunc Да, я знаю. Люди всегда жалуются на C / CLI, хотя на самом деле это отличный способ смешать управляемый и машинный код. Тем не менее, помимо того, что это довольно многословно, внедрение Mono не так уж плохо, учитывая, что большинство этих вызовов выполняются только один раз (вы будете повторно использовать дескрипторы MonoDomain , MonoAssembly , MonoImage MonoClass и MonoMethod ). Если вы уже имели дело с функциями языка высокого уровня во время выполнения (что является большим «если»), то здесь нет ничего удивительного.

3. Интересно, изменилось ли что-нибудь после выпуска .net core? Есть ли у него api для извлечения из собственного приложения objective c и экспорта классов в него?

Ответ №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 не включает NSTask API, поэтому там это невозможно. Я слышал о некоторых людях, использующих MonoTouch для создания приложений iOS на C #, но, как вы предложили, я думаю, вам лучше придерживаться Objective-C для большей части вашего приложения, если это возможно. Использование CLI-приложения, подобного описанному вами, определенно является опцией на Mac и может быть особенно полезно, когда у вас есть уже написанный и протестированный и работающий код, который вы просто хотите «обернуть» с помощью Cocoa GUI.

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

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

РЕДАКТИРОВАТЬ: я не знаком с C / CLI как языком, и я неверно истолковал значение C / CLI как «приложение с интерфейсом командной строки C «. Тем не менее … методы, которые я описал, все еще применяются как возможные методы для выполнения того, что вы хотите сделать, но при этом НЕ используется интерфейс C / CLI, как вы можете в Windows.