Сохранение значений в .Net приложение на этапе сборки

в 11:47, , рубрики: .net

Появилась у меня необходимость при сборке приложения передать внутрь набор констант для использования их на рантайме. Например, мы хотим «зашить» в приложение некое строковое значение которое будет известно в момент сборки.

В мире C++ я решал подобные штуки очень просто с использованием define и опций компилятора. Но в .Net define не имеют значений кроме true/false, т.е. они либо определены либо нет. Насколько я понимаю, их цель это простейшая условная компиляция.

Кому интересно решение добро пожаловать под кат.

Первая мысль, которая меня посетила: перед билдом сгенерить файлик с константами по шаблону, но хотелось бы обойтись без привлечения тяжелой артиллерии шаблонизаторов.

После некоторых поисков я обнаружил интересный факт. В .Net есть механизм атрибутов. Эти атрибуты можно цеплять к классам, методам, полям и всяким разным сущностям. Оказалось что его можно цепануть ко всей сборке целиком.

В файлах проектов (.csproj) есть возможность выставлять значения этим атрибутам при сборке. А в MSBuild можно передать параметры извне через механизм пропертей. Вроде все сходится, надо пробовать.

Создаем новое консольное приложение:

% mkdir Example && cd Example
% dotnet new console

Создаем файл ExampleAttribute.cs с определением нашего атрибута.

using System;

namespace Example
{

[AttributeUsage(AttributeTargets.Assembly)] //Указываем что атрибут цепляется к сборке
public class ExampleAttribute : Attribute
{
    public string Value { get; set; }

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

Далее файл Example.csproj приводим к следующему виду. Я добавил комментарии, дабы суть изменений была ясна.

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

Ну и собственно получение значения на рантайме в 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}'");
        }
    }
}

Итак соберем и запустим, дабы посмотреть что у нас получилось.

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

А теперь с параметром:

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

Вуаля, цель достигнута. Пользуйтесь на здоровье.

Автор: mpak65536

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js