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

?v=1

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

В мире 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 приводим к следующему виду. Я добавил комментарии, дабы суть изменений была ясна.



  
    Exe
    netcoreapp3.1
    Example

    default 
  

  
  
     
      <_Parameter1>$(ExampleValue) 
    
  



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


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

© Habrahabr.ru