我可以从csharp中的编译时env变量中创建一个常量吗?

时间:2010-12-15 13:12:18

标签: c# environment-variables compile-time

我们使用Hudson来构建我们的项目,Hudson在编译时方便地定义了像“%BUILD_NUMBER%”这样的环境变量。

我想在代码中使用该变量,因此我们可以在运行时记录这是什么构建。但是我不能做System.Environment.GetEnvironmentVariable,因为那是访问运行时环境,我想要的是:

#define BUILD_NUM = %BUILD_NUMBER%

const string BUILD_NUM = %BUILD_NUMBER%

除了我不知道语法。有人可以指点我正确的方向吗?谢谢!

5 个答案:

答案 0 :(得分:18)

好的,这就是我最后做的事情。它不是很优雅,但它有效。我创建了一个预构建步骤,如下所示:

echo namespace Some.Namespace > "$(ProjectDir)\CiInfo.cs"
echo { >> "$(ProjectDir)\CiInfo.cs"
echo     ///^<summary^>Info about the continuous integration server build that produced this binary.^</summary^> >> "$(ProjectDir)\CiInfo.cs"
echo     public static class CiInfo >> "$(ProjectDir)\CiInfo.cs"
echo     { >> "$(ProjectDir)\CiInfo.cs"
echo         ///^<summary^>The current build number, such as "153"^</summary^> >> "$(ProjectDir)\CiInfo.cs"
echo         public const string BuildNumber = ("%BUILD_NUMBER%" == "" ? @"Unknown" : "%BUILD_NUMBER%"); >> "$(ProjectDir)\CiInfo.cs"
echo         ///^<summary^>String of the build number and build date/time, and other useful info.^</summary^> >> "$(ProjectDir)\CiInfo.cs"
echo         public const string BuildTag = ("%BUILD_TAG%" == "" ? @"nohudson" : "%BUILD_TAG%") + " built: %DATE%-%TIME%"; >> "$(ProjectDir)\CiInfo.cs"
echo     } >> "$(ProjectDir)\CiInfo.cs"
echo } >> "$(ProjectDir)\CiInfo.cs"

然后我将“CiInfo.cs”添加到项目中,但是从版本控制中忽略了它。这样我就不必编辑或提交它,并且项目总是有一个常量可用,即最新的构建号和时间。

答案 1 :(得分:6)

一种方法是在编译之前添加一个构建步骤,在%BUILD_NUMBER%的相应源文件中执行正则表达式替换。

答案 2 :(得分:1)

define不允许您像在C / C ++中那样在C#中定义内容。

来自this page

#define指令不能用于声明常量值,这通常在C和C ++中完成。 C#中的常量最好定义为类或结构的静态成员。如果你有几个这样的常量,可以考虑创建一个单独的“常量”类来保存它们。

如果您希望在AssemblyInfo类中反映内部版本号,则大多数构建工具都支持在构建时生成该类。 MSBuild has a task为此。 As does NAnt。不确定哈德森是怎么做到的。

答案 3 :(得分:1)

一种可能性是使用T4生成配置类,并实例化所有常量。 T4很好地集成到MSVS中,无需您自己的自定义构建步骤。

答案 4 :(得分:1)

我有类似的问题。

我正在开发带有ASP.Net后端的Xamarin移动应用程序。我有一个包含后端服务器URL的设置类:

namespace Company.Mobile
{
    public static class Settings
    {
#if DEBUG
        const string WebApplicationBaseUrl = "https://local-pc:44335/";
#else
        const string WebApplicationBaseUrl = "https://company.com/";
#endif
    }
}

对于调试和发行版配置,它具有不同的值。但这在几个开发人员开始从事该项目时不起作用。每台开发机都有其IP地址,移动电话需要使用唯一的IP地址进行连接。

我需要从每个开发机上的文件或环境变量中设置常量值。这是Fody的合适位置。我用它来创建in solution weaver。这是the details

我将Settings类放在Xamarin应用程序项目中。该项目必须包含Fody Nuget软件包:

<ItemGroup>
    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Fody" Version="6.2.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
    <WeaverFiles Include="$(SolutionDir)Company.Mobile.Models\bin\Debug\netstandard2.0\Company.Mobile.Models.dll" WeaverClassNames="SetDevServerUrlWeaver" />
  </ItemGroup>

我仅使设置适用于Debug配置,因为我不希望替换版本在Release版本中发生。

weaver类放置在移动项目所依赖的类库项目(Company.Mobile.Models)中(您不必也不应具有此依赖关系,但是Fody docs清楚地表明包含该项目的项目编织器必须在发出编织组合的项目之前构建。该库项目包括FodyHelpers Nuget软件包:

<ItemGroup Condition="'$(Configuration)' == 'Debug'">
        <PackageReference Include="FodyHelpers" Version="6.2.0" />
    </ItemGroup>

weaver类的定义如下:

#if DEBUG

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Fody;

namespace Company.Mobile.Models
{
    public class SetDevServerUrlWeaver : BaseModuleWeaver
    {
        private const string SettingsClassName = "Settings",
            DevServerUrlFieldName = "WebApplicationBaseUrl",
            DevServerUrlSettingFileName = "devServerUrl.txt";

        public override void Execute()
        {
            var target = this.ModuleDefinition.Types.SingleOrDefault(t => t.IsClass && t.Name == SettingsClassName);

            var targetField = target.Fields.Single(f => f.Name == DevServerUrlFieldName);

            try
            {
                targetField.Constant = File.ReadAllText(Path.Combine(this.ProjectDirectoryPath, DevServerUrlSettingFileName));
            }
            catch
            {
                this.WriteError($"Place a file named {DevServerUrlSettingFileName} and place in it the dev server URL");

                throw;
            }
        }

        public override IEnumerable<string> GetAssembliesForScanning()
        {
            yield return "Company.Mobile";
        }
    }
}

#endif

这是放在移动应用程序项目中的FodyWeavers.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <SetDevServerUrlWeaver />
</Weavers>

devServerUrl.txt仅包含我的本地IP: https://192.168.1.111:44335/。不得将此文件添加到源代码管理中。将其添加到源代码管理忽略文件中,以便每个开发人员都有其版本。

您可以轻松地从环境变量(System.Environment.GetEnvironmentVariable)或任何地方(而不是文件)读取替换值。

我希望有更好的方法可以做到这一点,例如罗斯林(Roslyn)或this attribute似乎可以胜任,但事实并非如此。