Mezclar C# con Objective-C


Me gustaría usar un cuerpo más grande de código C# como una biblioteca para la aplicación Objective-C (Cocoa).

Descubrí el proyecto MonoMac que envuelve el código Cocoa, pero preferiría tener una aplicación Cocoa estándar escrita en Objective-C, que puede llamar al código C# envuelto (al revés).

En Windows estoy acostumbrado a hacer un proyecto de C++/CLI que envuelve el código.NET y exporta la antigua interfaz de C para aplicaciones basadas en C/C++.

¿Hay alguna forma sencilla de lograr esto?

Author: Moshe, 2011-04-17

2 answers

Obviamente no existe un lenguaje como C++/CLI en Mac OS. En Windows, C++/CLI en realidad compila como código administrado ejecutado por el CLR, que ejecuta código nativo; ya que en Mac OS Mono no está integrado al sistema, es más bien al revés. Tu aplicación es nativa y puede alojar código administrado.

Mono expone funciones para alojar una máquina virtual CLR dentro de un proceso. Dado que las clases CLR no están directamente expuestas a su código C, podrá llamar a métodos de objetos a través de llamadas de reflexión.

Hay documentación sobre cómo incrustar Mono en una aplicación en el sitio oficial. Dado que no está interesado en ejecutar programas.NET directamente, debería leer la sección "Invocar métodos en el Universo CIL". En Mac OS, querrás enlazar con el framework Mono desde tu carpeta /Library/Frameworks, en lugar de usar pkg-config.

Esto realmente no debería reemplazar una lectura real del documento anterior, sino lo siguiente puede ser visto como una guía en cuanto a qué esperar:

#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);

Si no encuentra esto muy atractivo, es posible que desee ir al revés, como mencionó, y mirar MonoMac, que proporciona enlaces.NET a una gran parte de las API que puede querer usar en una aplicación Mac (Cocoa, CoreImage, CoreAlimation, etc.) y los medios para crear sus propios enlaces.

 15
Author: zneak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-11 21:48:52

Si estás haciendo esto en Mac, entonces sí, es posible. En iOS no tanto.

En Mac, si puede crear una aplicación CLI en MonoMac, puede llamar a su aplicación CLI desde su aplicación Objective-C usando NSTask. NSTask le permite lanzar fácilmente una herramienta de línea de comandos y luego capturar su salida e interactuar con ella. Para hacer esto, usted haría algo como:

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);

Normalmente, la forma en que desea hacer esto es incluir la aplicación CLI dentro de su paquete de aplicaciones. A continuación, puede obtener el ruta a la aplicación CLI usando NSBundles-pathForResource:OfType: method.

IOS no incluye la API NSTask, por lo que esto no es posible allí. He oído hablar de algunas personas que usan MonoTouch para hacer aplicaciones de iOS usando C#, pero como sugeriste, creo que es mejor que te quedes con Objective-C para la mayor parte de tu aplicación si es posible. Usar una aplicación CLI como la que describes es definitivamente una opción en Mac y puede ser particularmente útil cuando tienes un cuerpo de código que ya está escrito y probado y funciona que solo quieres "Envolver" con una GUI de Cacao.

Entonces, NSTask es una forma de hacer esto usando un ejecutable CLI externo envuelto en su paquete de aplicaciones. Por otro lado, es posible que se pregunte, ¿puede vincular su código de C# directamente a Objective-C?

Bueno, Objective-C es un superconjunto de C, y como tal, tiene todas las capacidades de C. Además, si usas Objective-C++ también tiene todas las capacidades de C++. Por lo tanto, SI usted puede conseguir MonoMac para generar una C o C++ estática biblioteca, entonces sí, incluso podría vincular su biblioteca estática con su código de cacao Objective-C, y simplemente funcionará. No puedo decirte cómo hacer la biblioteca desde MonoMac, pero vincularla es solo cuestión de agregarla a tus bibliotecas vinculadas en la configuración de compilación en Xcode.

EDIT: No estoy familiarizado con C++/CLI como lenguaje, y malinterpreté el significado de C++/CLI para significar "Aplicación de Interfaz de Línea de comandos de C++". Dicho esto... las técnicas que describí todavía se aplican como posibles métodos para hacer lo que quieres hacer, pero NO está usando la interfaz C++/CLI como puedes hacerlo en Windows.

 3
Author: Jiva DeVoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-18 03:56:01