إعادة تعريف البيان من .ساعة الملف في التعليمات البرمجية C#

StackOverflow https://stackoverflow.com/questions/100854

سؤال

لدي C++ المشروع (VS2005) والذي يتضمن الملف رأس مع رقم الإصدار في #تعريف التوجيه.الآن أنا في حاجة إلى تضمين بالضبط نفس العدد في التوأم مشروع C#.ما هي أفضل طريقة للقيام بذلك ؟

أنا أفكر بما فيها هذا الملف كمورد ، ثم تحليل ذلك في وقت التشغيل مع regex لاسترداد رقم الإصدار, ولكن ربما هناك طريقة أفضل, ما رأيك ؟

أنا لا يمكن أن تتحرك نسخة في الخارج .ساعة الملف أيضا بناء نظام يعتمد على ذلك و C# مشروع واحد هو الذي ينبغي تكييفها.

هل كانت مفيدة؟

المحلول

يمكنك تحقيق ما تريد في بضع خطوات فقط:

  1. إنشاء MSBuild المهمة - http://msdn.microsoft.com/en-us/library/t9883dzc.aspx
  2. تحديث ملف المشروع أن تتضمن دعوة إلى المهمة التي تم إنشاؤها قبل بناء

المهمة يتلقى المعلمة مع موقع رأس .ساعة الملف المشار إليه.ثم تستخرج نسخة ووضع هذا الإصدار في C# نائبا ملف كنت سابقا قد خلقت.أو يمكنك التفكير باستخدام AssemblyInfo.cs التي عادة ما يحمل إصدارات إذا كان هذا هو موافق لك.

إذا كنت بحاجة إلى معلومات إضافية يرجى لا تتردد في التعليق.

نصائح أخرى

وأود أن تنظر في استخدام .tt ملف العملية .ح وتحويلها إلى .cs الملف.من السهل جدا و الملفات المصدر ثم يكون جزء من C# الحل (يعني أنها سوف تكون منتعشة كما .ح تغييرات الملف), يمكن النقر على فتح في محرر ، إلخ.

إذا كنت قد حصلت فقط 1 #تعريف قد تكون مبالغة ، ولكن إذا كان لديك ملف كامل منهم (على سبيل المثال mfc الموارد.ساعة الملف ربما) ثم هذا الحل يصبح فوز كبير.

على سبيل المثال:إنشاء ملف DefineConverter.tt وإضافته إلى المشروع الخاص بك, تغيير خط ملحوظ إلى الرجوع إلى الخاص بك .ساعة الملف و ستحصل على فئة جديدة في المشروع الخاص بك كامل من ثابت const الإدخالات.(ملاحظة ملف الإدخال نسبة إلى ملف المشروع مجموعة hostspecific=false إذا كنت تريد مسارات مطلقة).

<#@ 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]#>";
<#
            }
        }
    } #> 
    }
}

MSDN يقول لنا:

رقم تعريف التوجيه لا يمكن استخدامها تعلن قيم ثابتة كما هو عادة يتم في C و C++.الثوابت في C# هي أفضل تعريف ثابت أعضاء فئة أو البنية.إذا كنت لدينا العديد من هذه الثوابت ، والنظر في إنشاء منفصلة "الثوابت" الطبقة عقد لهم.

يمكنك إنشاء مكتبة باستخدام C++ مدارة تتضمن فئة - التفاف حول الثوابت.ثم يمكنك الرجوع إلى هذه الدرجة من مشروع C#.فقط لا تنسى أن استخدام للقراءة فقط < نوع > بدلا من const < نوع > الخاص بك الثوابت الإعلان :)

يمكنك دائما استخدام pre-build لتشغيل ج المعالج على .cs الملف و بعد بناء الحدث إلى التراجع عن ما قبل بناء الخطوة.المعالج هو مجرد نص إحلال النظام ، لذلك هذا ممكن:

// version header file
#define Version "1.01"

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

و المعالج سوف تولد:

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

يمكنك كتابة بسيطة C++/C الأداة التي تتضمن هذا .ح ملف حيوي إنشاء الملفات التي يمكن استخدامها في C#.
هذه الأداة يمكن تشغيل كجزء من مشروع C# قبل بناء المرحلة.
بهذه الطريقة يمكنك دائما متزامنة مع الملف الأصلي.

كتبت بيثون السيناريو الذي يحول #تعريف فو "بار" إلى شيء قابل للاستخدام في C# و أنا استخدامه في مرحلة ما قبل بناء خطوة في مشروع C#.أنه يعمل.

# 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'

بناء على gbjbaanb حل, أنا خلقت .tt الملف الذي يرى كل شيء .ساعة الملفات في دليل معين وفات منهم إلى .cs الملف مع فئات متعددة.

الاختلافات

  • لقد تم إضافة الدعم الزوجي
  • تحولت من المحاولة-catch إلى TryParse
  • يقرأ متعددة .ملفات h
  • يستخدم 'للقراءة فقط' بدلا من 'const'
  • الديكورات #تحديد الخطوط التي تنتهي في ;
  • مساحة قائم على أساس .tt موقع في المشروع

<#@ 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]#>";
<#          
            }
        }
    } #>
    }
<#}#>     
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top