Tuesday, April 24, 2012

CXXI: Мост между мирами C# и C++

В рантайме Mono есть немало средств для взаимодействия с кодом на не .NET языках, но никогда не было ничего вменяемого для взаимодействия с кодом на C++.

Но это вскоре изменится благодаря работе Алекса Коррадо, Андрэа Гайта и Зольтана Варга.

Вкратце, новая технология позволяет разработчикам C#/.NET:

Легко и прозрачно использовать классы C++ из C# или любого иного .NET языка
Создавать экземпляры классов C++ из C#
Вызывать методы классов C++ из кода на C#
Вызывать инлайн-методы C++ из кода на C# (при условии, что библиотека скомпилирована с флагом -fkeep-inline-functions или если вы скомпилируете дополнительную библиотеку с их реализациями)
Наследовать классы C++ из C#
Переопределять виртуальные методы классов C++ методами на C#
Использовать экземпляры таких смешанных C++/C# классов как в коде на C#, так и в коде на C++

CXXI (прим. пер.: читается как «sexy») это результат двухмесячной работы под эгидой Google's Summer of Code с целью улучшить взаимодействие Mono с кодом на C++.

Альтернативы

Напоминаю, что Mono предоставляет несколько механизмов взаимодействия с кодом на не .NET языках, большей частью унаследованные из ECMA-стандарта. Эти механизмы включают: 
Двухсторонняя технология «Platform Invoke» (P/Invoke), позволяющая управляемому коду (C#) вызывать функции из неуправляемых библиотек, а коду этих библиотек делать callback'и обратно в управляемый код.
COM Interop позволяющий коду, выполняющемуся в Mono прозрачно вызывать неуправляемый код на C или C++ до тех пор пока этот код соблюдает некоторые конвенции COM (конвенции эти довольно простые: стандартная «разметка» vtable, реализация методов Add, Release и QueryInterface, а так же использование стандартного набора типов, которые могут быть отмаршалены между Mono и COM-библиотекой).
Общая технология перехвата вызовов, позволяющая перехватить вызов метода объекта и дальше самостоятельно разбираться с тем, что с ним делать.

Но когда дело доходит до того чтобы использовать в C# объекты C++, выбор остаётся не очень-то обнадёживающий. Для примера, предположим что вы хотите из C# использовать следующий класс C++:

class MessageLogger {
public:
    MessageLogger (const char *domain);
    void LogMessage (const char *msg);
}

Одним из способов предоставить этот класс коду на C# — обернуть его в COM-объект. Это может сработать для некоторых высокоуровневых объектов, но процесс оборачивания весьма нудный и рутинный. Посмотреть, как выглядит это неинтересное занятие можно тут.

Другой вариант — наклепать переходников, которые потом можно будет вызвать через P/Invoke. Для представленного выше класса выглядеть они будут примерно так: 

/* bridge.cpp, компилируется в bridge.so */
MessageLogger *Construct_MessageLogger (const char *msg)
{
    return new MessageLogger (msg);
}

void LogMessage (MessageLogger *logger, const char *msg)
{
    logger->LogMessage (msg);
}

Часть на C# выглядит так:
class MessageLogger {
    IntPtr handle;

    [DllImport ("bridge")]
    extern static IntPtr Construct_MessageLogger (string msg);

    public MessageLogger (string msg)
    {
        handle = Construct_MessageLogger (msg);
    }

    [DllImport ("bridge")]
    extern static void LogMessage (IntPtr handle, string msg);

    public void LogMessage (string msg)
    {
        LogMessage (handle, msg);
    }
}

Read more: Habrahabr.ru
QR: Inline image 1

Posted via email from Jasper-Net