2008-09-19 25 views
6

Tôi có dự án C++ (VS2005) bao gồm tệp tiêu đề có số phiên bản trong chỉ thị #define. Bây giờ tôi cần bao gồm chính xác cùng một số trong dự án C# đôi. Cách tốt nhất để làm điều đó là gì?Tái sử dụng câu lệnh xác định từ tệp .h trong C# code

Tôi đang nghĩ đến việc bao gồm tệp này làm tài nguyên, sau đó phân tích cú pháp tại thời gian chạy với regex để khôi phục số phiên bản, nhưng có thể có cách tốt hơn, bạn nghĩ sao?

Tôi không thể di chuyển phiên bản bên ngoài tệp .h, cũng xây dựng hệ thống phụ thuộc vào nó và dự án C# là một dự án cần được điều chỉnh.

Trả lời

2

Bạn có thể đạt được những gì bạn muốn chỉ trong một vài bước sau:

  1. Tạo một tác vụ MSBuild - http://msdn.microsoft.com/en-us/library/t9883dzc.aspx
  2. Cập nhật tệp dự án để bao gồm một cuộc gọi đến tác vụ được tạo trước khi xây dựng

Nhiệm vụ nhận được thông số với vị trí của tệp .h tiêu đề bạn đã giới thiệu. Sau đó nó trích xuất phiên bản và đặt phiên bản đó trong một tệp phần giữ chỗ C# mà trước đó bạn đã tạo. Hoặc bạn có thể nghĩ rằng bằng cách sử dụng AssemblyInfo.cs mà thường giữ các phiên bản nếu đó là ok cho bạn.

Nếu bạn cần thêm thông tin, vui lòng nhận xét.

3

MSDN cho chúng ta biết:

Chỉ thị #define không thể sử dụng để khai báo giá trị không đổi như là thường được thực hiện trong C và C++. Các hằng số trong C# được xác định rõ nhất là static thành viên của một lớp hoặc cấu trúc. Nếu bạn có một số hằng số như vậy, hãy xem xét tạo một lớp "Constants" riêng biệt để giữ chúng.

Bạn có thể tạo thư viện bằng cách sử dụng managed C++ bao gồm lớp - trình bao bọc xung quanh các hằng số của bạn. Sau đó, bạn có thể tham khảo lớp này từ dự án C#. Chỉ cần đừng quên sử dụng readonly < type> thay vì const < type> khai báo hằng số của bạn :)

2

Bạn luôn có thể sử dụng các sự kiện trước khi xây dựng để chạy tiền xử lý C vào file .cs và sự kiện xây dựng bài đăng để hoàn tác bước tạo trước. Preprocessor chỉ là một hệ thống văn bản thay thế, vì vậy đây có thể:

// version header file 
#define Version "1.01" 

// C# code 
#include "version.h" 
// somewhere in a class 
string version = Version; 

và tiền xử lý sẽ tạo ra:

// C# code 
// somewhere in a class 
string version = "1.01"; 
+0

này chỉ có vẻ câu trả lời rõ ràng và dễ hiểu nhất đối với tôi. –

1

Bạn có thể viết tiện ích C++/C đơn giản bao gồm tệp .h này và tự động tạo tệp có thể được sử dụng trong C#.
Tiện ích này có thể được chạy như một phần của dự án C# dưới dạng giai đoạn dựng sẵn.
Bằng cách này, bạn luôn đồng bộ hóa với tệp gốc.

0

Tôi đã viết một tập lệnh python chuyển đổi #define FOO "bar" thành một cái gì đó có thể sử dụng trong C# và tôi đang sử dụng nó trong một bước dựng sẵn trong dự án C# của tôi. Nó hoạt động.

# translate the #defines in messages.h file into consts in MessagesDotH.cs 

import re 
import os 
import stat 

def convert_h_to_cs(fin, fout): 
    for line in fin: 
     m = re.match(r"^#define (.*) \"(.*)\"", line) 
     if m != None: 
      if m.group() != None: 
       fout.write("public const string " \ 
       + m.group(1) \ 
       + " = \"" \ 
       + m.group(2) \ 
       + "\";\n") 
     if re.match(r"^//", line) != None: 
      fout.write(line) 

fin = open ('..\common_cpp\messages.h') 
fout = open ('..\user_setup\MessagesDotH.cs.tmp','w') 

fout.write('using System;\n') 
fout.write('namespace xrisk { class MessagesDotH {\n') 

convert_h_to_cs(fin, fout) 

fout.write('}}') 

fout.close() 

s1 = open('..\user_setup\MessagesDotH.cs.tmp').read() 

s2 = open('..\user_setup\MessagesDotH.cs').read() 

if s1 != s2: 
    os.chmod('..\user_setup\MessagesDotH.cs', stat.S_IWRITE) 
    print 'deleting old MessagesDotH.cs' 
    os.remove('..\user_setup\MessagesDotH.cs') 
    print 'remaming tmp to MessagesDotH.cs' 
    os.rename('..\user_setup\MessagesDotH.cs.tmp','..\user_setup\MessagesDotH.cs') 
else: 
    print 'no differences. using same MessagesDotH.cs' 
5

Tôi sẽ xem xét sử dụng tệp .tt để xử lý .h và biến tệp thành tệp .cs. Các tệp nguồn của nó rất dễ dàng và sau đó sẽ là một phần của giải pháp C# của bạn (có nghĩa là chúng sẽ được làm mới dưới dạng tệp .h thay đổi), có thể được nhấp vào để mở trong trình chỉnh sửa, v.v.

Nếu bạn chỉ có có 1 # define nó có thể là một chút overkill, nhưng nếu bạn có một tập tin đầy đủ của họ (ví dụ như một tập tin mfc resource.h có lẽ) thì giải pháp này sẽ trở thành một chiến thắng lớn.

ví dụ: tạo tệp, DefineConverter.tt và thêm nó vào dự án của bạn, thay đổi dòng được đánh dấu để tham chiếu đến tệp .h của bạn và bạn sẽ nhận được một lớp mới trong dự án của bạn đầy đủ các mục nhập const tĩnh. (lưu ý tệp đầu vào có liên quan đến tệp dự án của bạn, đặt hostspecific = false nếu bạn muốn đường dẫn tuyệt đối).

<#@ template language="C#v3.5" hostspecific="True" debug="True" #> 
<#@ output extension="cs" #> 
<#@ assembly name="System.Core.dll" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ import namespace="System.IO" #> 

<# 
string input_file = this.Host.ResolvePath("resource.h");    <---- change this 
StreamReader defines = new StreamReader(input_file); 
#> 
//------------------------------------------------------------------------------ 
//  This code was generated by template for T4 
//  Generated at <#=DateTime.Now#> 
//------------------------------------------------------------------------------ 

namespace Constants 
{ 
    public class <#=System.IO.Path.GetFileNameWithoutExtension(input_file)#> 
    { 
<# 
    // constants definitions 

    while (defines.Peek() >= 0) 
    { 
     string def = defines.ReadLine(); 
     string[] parts; 
     if (def.Length > 3 && def.StartsWith("#define")) 
     { 
      parts = def.Split(null as char[], StringSplitOptions.RemoveEmptyEntries); 
      try { 
       Int32 numval = Convert.ToInt32(parts[2]); 
       #> 
     public static const int <#=parts[1]#> = <#=parts[2]#>; 
<# 
      } 
      catch (FormatException e) { 
      #> 
     public static const string <#=parts[1]#> = "<#=parts[2]#>"; 
<# 
      } 
     } 
    } #> 
    } 
} 
0

xây dựng trên giải pháp gbjbaanb, tôi đã tạo ra một tập tin .tt mà tìm thấy tất cả các file .h trong một thư mục cụ thể và cuộn chúng thành một file .cs với nhiều lớp.

khác biệt

  • tôi thêm hỗ trợ cho đôi
  • Switched từ try-catch để TryParse
  • Đọc nhiều file .h 'readonly'
  • Sử dụng thay vì 'const'
  • tính kỹ thuật # xác định các dòng kết thúc bằng ;
  • Namespace được thiết lập dựa trên vị trí .tt trong dự án

<#@ template language="C#" hostspecific="True" debug="True" #> 
<#@ output extension="cs" #> 
<#@ assembly name="System.Core.dll" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ import namespace="System.IO" #> 
<# 
string hPath = Host.ResolveAssemblyReference("$(ProjectDir)") + "ProgramData\\DeltaTau\\"; 
string[] hFiles = System.IO.Directory.GetFiles(hPath, "*.h", System.IO.SearchOption.AllDirectories); 
var namespaceName = System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint"); 
#> 
//------------------------------------------------------------------------------ 
//  This code was generated by template for T4 
//  Generated at <#=DateTime.Now#> 
//------------------------------------------------------------------------------ 

namespace <#=namespaceName#> 
{ 
<#foreach (string input_file in hFiles) 
{ 
StreamReader defines = new StreamReader(input_file); 
#> 
    public class <#=System.IO.Path.GetFileNameWithoutExtension(input_file)#> 
    { 
<# // constants definitions 

    while (defines.Peek() >= 0) 
    { 
     string def = defines.ReadLine(); 
     string[] parts; 
     if (def.Length > 3 && def.StartsWith("#define")) 
     { 
      def = def.TrimEnd(';'); 
      parts = def.Split(null as char[], StringSplitOptions.RemoveEmptyEntries); 
      Int32 intVal; 
      double dblVal; 
      if (Int32.TryParse(parts[2], out intVal)) 
      { 
      #> 
     public static readonly int <#=parts[1]#> = <#=parts[2]#>;   
<# 
      } 
      else if (Double.TryParse(parts[2], out dblVal)) 
      { 
      #> 
     public static readonly double <#=parts[1]#> = <#=parts[2]#>;    
<# 
      } 
      else 
      { 
      #> 
     public static readonly string <#=parts[1]#> = "<#=parts[2]#>"; 
<#   
      } 
     } 
    } #> 
    } 
<#}#>  
} 
Các vấn đề liên quan