Salvando valores em um aplicativo .Net no Build

Havia uma necessidade para mim ao criar o aplicativo para transmitir um conjunto de constantes para uso em tempo de execução. Por exemplo, queremos "costurar" no aplicativo algum valor de string que será conhecido no momento da montagem.

No mundo C ++, resolvi essas coisas muito simplesmente usando as opções define e compilador. Mas em .Net define não temos valores diferentes de verdadeiro / falso, ou seja, eles são identificados ou não. Pelo que entendi, o objetivo deles é a compilação condicional mais simples.

Quem se importa com a solução, bem-vindo ao gato.

O primeiro pensamento que me visitou foi gerar um arquivo com constantes de acordo com o modelo antes da compilação, mas eu gostaria de fazer isso sem envolver artilharia pesada dos mecanismos de modelo.

Após algumas pesquisas, descobri um fato interessante. .Net possui um mecanismo de atributo. Esses atributos podem se apegar a classes, métodos, campos e todos os tipos de entidades diferentes. Aconteceu que ele pode ser enganchado em toda a montagem.

Nos arquivos de projeto (.csproj), é possível definir valores para esses atributos durante a montagem. E no MSBuild, você pode passar parâmetros de fora através do mecanismo de propriedades. Parece que tudo se encaixa, você tem que tentar.

Crie um novo aplicativo de console:

% mkdir Example && cd Example
% dotnet new console

Criamos o arquivo ExampleAttribute.cs com a definição de nosso atributo.

using System;

namespace Example
{

[AttributeUsage(AttributeTargets.Assembly)] //     
public class ExampleAttribute : Attribute
{
    public string Value { get; set; }

    public ExampleAttribute(string value)
    {
        Value = value;
    }
}
 
}

Em seguida, o arquivo Example.csproj é reduzido para o seguinte formulário. Eu adicionei comentários para que a essência das mudanças fosse clara.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <RootNamespace>Example</RootNamespace>

    <ExampleValue>default</ExampleValue> <!--        -->
  </PropertyGroup>

  <!--          -->
  <ItemGroup>
    <AssemblyAttribute Include="Example.ExampleAttribute"> <!--    -->
      <_Parameter1>$(ExampleValue)</_Parameter1> <!--      -->
    </AssemblyAttribute>
  </ItemGroup>

</Project>

Bem, na verdade, obtendo o valor em tempo de execução no Project.cs

using System;
using System.Reflection;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var attr = (ExampleAttribute) assembly.GetCustomAttribute(typeof(ExampleAttribute));
            Console.WriteLine($"Assembly attribute value = '{attr.Value}'");
        }
    }
}

Então, vamos nos reunir e correr para ver o que temos.

% dotnet build .
% dotnet run --no-build .
Assembly attribute value = 'default'

E agora com o parâmetro:

% dotnet build . /p:ExampleValue="NOT DEFAULT"
% dotnet run --no-build .
Assembly attribute value = 'NOT DEFAULT'

Voila, o objetivo foi alcançado. Use na saúde.

All Articles