Сохранение значений в .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' 

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

ссылка на оригинал статьи https://habr.com/ru/post/492216/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *