Я пытаюсь использовать protobuf в проекте C #, используя protobuf-net, и мне интересно, как лучше всего организовать это в структуру проекта Visual Studio.
Когда вы вручную используете инструмент Protogen для генерации кода в C #, жизнь кажется простой, но не совсем правильной.
Я бы хотел, чтобы файл .proto считался основным файлом исходного кода, генерируя файлы C # как побочный продукт, но до того, как в него включился компилятор C #.
Возможны следующие варианты:
- Пользовательский инструмент для инструментов прото (хотя я не вижу, с чего начать)
- Шаг предварительной сборки (вызов протогена или пакетного файла, который делает это)
Я боролся с 2) выше, так как он продолжает давать мне «Системе не удается найти указанный файл», если я не использую абсолютные пути (и я не люблю принудительно определять местоположение проектов).
Есть ли соглашение (пока) для этого?
Edit:
Основываясь на комментариях @ jon, я повторил метод шага перед сборкой и использовал его (на данный момент местоположение протогена жестко задано), используя пример адресной книги Google:
c:\bin\protobuf\protogen "-i:$(ProjectDir)AddressBook.proto"
"-o:$(ProjectDir)AddressBook.cs" -t:c:\bin\protobuf\csharp.xslt
Edit2:
Принимая во внимание рекомендацию @ jon минимизировать время сборки, не обрабатывая файлы .proto, если они не изменились, я собрал основной инструмент для проверки (возможно, его можно расширить до полного инструмента Custom-Build):
using System;
using System.Diagnostics;
using System.IO;
namespace PreBuildChecker
{
public class Checker
{
static int Main(string[] args)
{
try
{
Check(args);
return 0;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return 1;
}
}
public static void Check(string[] args)
{
if (args.Length < 3)
{
throw new ArgumentException(
"Command line must be supplied with source, target and command-line [plus options]");
}
string source = args[0];
string target = args[1];
string executable = args[2];
string arguments = args.Length > 3 ? GetCommandLine(args) : null;
FileInfo targetFileInfo = new FileInfo(target);
FileInfo sourceFileInfo = new FileInfo(source);
if (!sourceFileInfo.Exists)
{
throw new ArgumentException(string.Format(
"Source file {0} not found", source));
}
if (!targetFileInfo.Exists ||
sourceFileInfo.LastWriteTimeUtc > targetFileInfo.LastAccessTimeUtc)
{
Process process = new Process();
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.ErrorDialog = true;
Console.WriteLine(string.Format(
"Source newer than target, launching tool: {0} {1}",
executable,
arguments));
process.Start();
}
}
private static string GetCommandLine(string[] args)
{
string[] arguments = new string[args.Length - 3];
Array.Copy(args, 3, arguments, 0, arguments.Length);
return String.Join(" ", arguments);
}
}
}
Моя команда перед сборкой теперь (все в одной строке):
$(SolutionDir)PreBuildChecker\$(OutDir)PreBuildChecker
$(ProjectDir)AddressBook.proto
$(ProjectDir)AddressBook.cs
c:\bin\protobuf\protogen
"-i:$(ProjectDir)AddressBook.proto"
"-o:$(ProjectDir)AddressBook.cs"
-t:c:\bin\protobuf\csharp.xslt