2011-04-17 12 views
29

Me gustaría utilizar un cuerpo más grande del código C# como biblioteca para la aplicación Objective-C (Cocoa).Mezcla C# con Objective-C

Descubrí el proyecto MonoMac que envuelve el código Cocoa, pero prefiero tener la 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 crear proyectos C++/CLI que envuelven el código .NET y exportan la antigua interfaz C simple para aplicaciones basadas en C/C++.

¿Hay alguna manera simple de lograr esto?

+0

Esa es en realidad una pregunta bastante interesante. No sé cuál es la respuesta, pero estoy interesado en ver qué dice la gente sobre esto. –

+1

... y es por eso que tenemos el botón de votación. – vidstige

Respuesta

14

No existe, obviamente, ningún lenguaje como C++/CLI en Mac OS. En Windows, C++/CLI en realidad se 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 al revés. Su aplicación es nativa y puede alojar código administrado.

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

Hay documentation on how to embed Mono into an application en el sitio oficial. Como no está interesado en running .NET programs directly, debería leer la sección "Invoking Methods in the CIL Universe".En Mac OS, querrá establecer un vínculo con el marco de Mono desde su carpeta /Library/Frameworks, en lugar de usar pkg-config.

Esto realmente no debe reemplazar una lectura real del documento anterior, pero el siguiente puede ser visto como una guía en cuanto a lo que puede 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 este muy atractivo, Es posible que desee ir al revés, como mencionó, y consulte MonoMac, que proporciona enlaces .NET a una gran parte de las API que puede utilizar en una aplicación Mac (Cocoa, CoreImage, CoreAnimation, etc.) y significa crear tus propias ataduras.

+0

Gracias. Esto parece una posible forma. Pero no es simple :( –

+2

@Filip Kunc Sí, lo sé. La gente siempre se queja de C++/CLI, aunque en realidad es una excelente manera de mezclar el código administrado y el nativo. Sin embargo, aparte de ser bastante detallado, incrustar Mono no es tan malo teniendo en cuenta que la mayoría de esas llamadas se realizan solo una vez (reutilizarás los manejadores 'MonoDomain',' MonoAssembly', 'MonoImage',' MonoClass' y 'MonoMethod'). Si ya tienes una alta las funciones de tiempo de ejecución del lenguaje de nivel (que es un gran si), no hay nada bastante sorprendente aquí. – zneak

3

Si está 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 utilizando 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); 

Por lo general, la forma en que quiere hacer esto, es incluir la aplicación CLI dentro de su paquete de aplicación. A continuación, puede obtener la ruta a la aplicación CLI utilizando NSBundles -pathForResource: ofType: method.

iOS no incluye la API de NSTask, por lo que no es posible. He oído de algunas personas que usan MonoTouch para hacer aplicaciones de iOS usando C#, pero como sugirió, creo que es mejor que se quede con Objective-C para la mayor parte de su aplicación si es posible. Usar una aplicación de 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 "Ajustar" con una GUI de Cocoa.

Por lo tanto, NSTask es una forma de hacerlo utilizando un ejecutable CLI externo incluido en su paquete de aplicaciones. Por otro lado, es posible que se pregunte, ¿puede vincular su código C# directamente en Objective-C?

Bueno, Objective-C es un superconjunto de C, y como tal, tiene todas las capacidades de C. Además, si usa Objective-C++ también tiene todas las capacidades de C++. Entonces, si puede hacer que MonoMac genere una biblioteca estática C o C++, 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 una cuestión de agregarla a tus bibliotecas vinculadas en tus configuraciones de compilación en Xcode.

EDIT: No estoy familiarizado con C++/CLI como un lenguaje, y yo mal interpretado el significado de C++/CLI para significar "aplicación C++ interfaz de línea de comandos". Dicho eso ... las técnicas que describí se siguen aplicando como métodos posibles para hacer lo que quieres hacer, pero NO utiliza la interfaz C++/CLI como lo haces en Windows.

Cuestiones relacionadas