Как я могу обработать определения C ++ в C #? - PullRequest
4 голосов
/ 06 октября 2011

У меня есть куча * .h файлов, содержащих только определения в стиле c, такие как

#define ALPHA_REACTOR_CODE 99641
#define BETA_REACTOR_CODE  99642
#define GAMMA_REACTOR_CODE 99643
#define DELTA_REACTOR_CODE 99644

Как я могу использовать эти файлы в моем коде С # без изменений и работать с этой константой в моем коде?

Ответы [ 4 ]

3 голосов
/ 07 октября 2011

извиняюсь за поздний ответ, когда я обещал один ранее.

У меня есть идея использовать компилятор кода времени выполнения, а также рефлексию для динамической генерации класса, который содержит все эти константы.

Итак, шаги (или псевдокод), как я вижу это:

  1. Для каждого файла .h прочитайте все строки, которые начинаются с #define, и сохраните их.
  2. Используя Microsoft.CSharp.CSharpCodeProvider() и пустой файл шаблона, скомпилируйте DLL в памяти, которая содержит класс, который предоставляет константы стиля public const int ALPHA_REACTOR_CODE = 99641;.
  3. Используйте Assembly.GetType(string), чтобы получить тип вашего сгенерированного класса
  4. Используйте Reflection и метод, который принимает имя константы для доступа к значению.

Так что, если это наш план атаки, вот несколько фрагментов кода, которые могут вам помочь.

1.Загрузка файлов .h Это довольно простое чтение файлов, ключевая хитрость состоит в том, чтобы отфильтровать ваши строки по #define и затем проанализировать Dictionary<string, int>.

lines.Where(line => line.StartsWith("#define", true, CultureInfo.CurrentCulture))
                .Select(line => line.Split(' ').Skip(1))
                .ToDictionary(lineParts => lineParts.First(), lineParts => int.Parse(lineParts.Last()));

. Это сгенерирует словарь.из всех ваших определений.Возможно, вы захотите сделать .Distict() вызов до .ToDictionary() на тот случай, если есть повторяющиеся определения.

2.Генерация сборки Здесь вы используете Microsoft.CSharp.CSharpCodeProvider() для генерации сборки в памяти.Хитрость заключается в том, чтобы иметь файл «GenerateCode.cs», который содержит базовую структуру для класса.Это должно быть установлено как EmbeddedResource, иначе он будет пытаться скомпилироваться (что не будет работать).

using System;

namespace GeneratedCode
{{
    public class GeneratedConstants
    {{

{0}

    }}
}}

Вы заметите {0}, мы используем это с string.Format длявставьте константы в файл.

Используйте assembly.GetManifestResourceStream(), чтобы получить поток этого файла шаблона, и обычный StreamReader, чтобы прочитать это в одну большую строку в памяти.

Генерация константиспользуя StringBuilder и базовое string.Format() форматирование в сочетании со словарем значений.

    StringBuilder builder = new StringBuilder();
    foreach (var constant in dict)
    {
        builder.AppendFormat(CultureInfo.CurrentCulture, "public const int {0} = {1};", constant.Key, constant.Value);
    }

Затем просто используйте string.Format (), чтобы вставить строку построителя в сгенерированную строку класса (используя {0})

Тогда вам просто нужно использовать Microsoft.CSharp.CSharpCodeProvider() для генерации сборки в памяти.

 using (CSharpCodeProvider provider = new CSharpCodeProvider())
            {
                parameters.ReferencedAssemblies.Add("System.dll");
                parameters.ReferencedAssemblies.Add("System.Core.dll");

                CompilerResults results = provider.CompileAssemblyFromSource(parameters, sourceCode);

            }

3 & 4. Теперь с помощью Reflection иметь сборку, которая содержит тип с определенными в нем константами, вы можете использовать assembly.GetType("GeneratedCode.GeneratedConstants");, чтобы получить тип, и использовать Reflection, чтобы вывести константы, по одной или все вместе.

ЕстьПосмотрите на этот пост, который описывает, как получить const, используяотражение: http://weblogs.asp.net/whaggard/archive/2003/02/20/2708.aspx

Ну, я надеюсь, это поможет вам.Это не слишком сложное решение, но имеет несколько движущихся частей.

Удачи!

2 голосов
/ 06 октября 2011

Напишите программу для преобразования файла .h стиля C в эквивалент C #.Если, как утверждается, файл .h содержит только int #defines, это должно быть довольно тривиально на выбранном вами языке.

В идеале преобразование должно быть правильно интегрировано в процесс сборки / создания, поэтому оно будет переделано, когда / если файл .h изменится.

1 голос
/ 06 октября 2011

Я не знаю, возможно ли то, что вы хотите.Однако, вот что стоит того: C #:

C # не поддерживает #define так же, как c ++.Я думаю, что вы должны были бы написать эти константы в виде перечисления или значения константы.например,

enum REACTOR
{
    ALPHA = 99641,
    BETA = 99642,
    GAMMA = 99643,
    DELTA = 99641
}

или используйте константы, так как эти значения заменяются во время компиляции

const int ALPHA_REACTOR = 99641;

Если у вас много этих значений (классы .h), я полагаю, вы могли бы сделатьконтейнерный «константный» класс, который хранит их все в отдельных перечислениях, описывающих значения внутри (REACTOR, X, Y, Z), так что вы можете просто вызвать Constants.REACTOR.ALPHA в своем коде.так как меня интересует фактический ответ на этот вопрос.Мне интересно, возможно ли то, что вы хотите сделать.

// edit Эта ссылка предлагает другой вариант, который я привел ниже.

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

Я бы порекомендовал это только после некоторых очень обширныхтестирование, так как я не уверен, что все реализации JIT действительно позволят это.

Это не то же самое, но еще один вариант, который генерирует дополнительный код C #.

0 голосов
/ 06 октября 2011

Может быть, вы хотите, чтобы управляемый C ++ интегрировал ваш код C с кодом C #?

...