Можно ли сделать директиву препроцессора зависимой от версии платформы.NET?

Вот конкретный пример того, что я хочу сделать.

Рассмотрим string.Join функция. До.NET 4.0 было только две перегрузки, обе из которых требовали string[] параметр.

Начиная с.NET 4.0, появились новые перегрузки, принимающие более гибкие типы параметров, включая IEnumerable<string>,

У меня есть библиотека, которая включает в себя Join функция, которая делает то, что.NET 4.0 string.Join функция делает. Мне было просто интересно, смогу ли я сделать реализацию этой функции зависимой от целевой платформы.NET. Если 4.0, он может просто позвонить string.Join внутренне. Если 3.5 или старше, он может вызвать свою собственную внутреннюю реализацию.

  1. Эта идея имеет смысл?
  2. Если это имеет смысл, какой самый логичный способ сделать это? Я думаю, я просто предполагаю, что директива препроцессора будет иметь смысл, так как вызов string.Join с IEnumerable<string> параметр не компилируется даже при таргетинге на версию.NET старше 4.0; поэтому любой подход, который я использую, должен был бы иметь место до компиляции. (Проверка Environment.Version свойство во время выполнения, например, не будет работать.)

4 ответа

Решение

Вы можете взглянуть на другой вопрос о переполнении стека, который иллюстрирует, как установить условные константы через XML-файл проекта: определить целевую версию платформы во время компиляции.

Затем, используя это, вы можете определить, следует ли использовать перегрузки.NET 4 или собственную библиотеку.

В какой-то момент (не знаю, когда) Microsoft добавила предопределенные символы для версий .NET в систему сборки MSBuild. Все здесь работает, если вы используете MSBuild из .NET 5+ SDK (даже если проект, который вы создаете с помощью этого SDK, использует гораздо более старую целевую платформу).

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives

Это позволяет вам, например, сделать это:

      #if NET5_0_OR_GREATER
    Console.WriteLine("This is .NET 5 or later.");
#elif NETCOREAPP
    Console.WriteLine("This is an older version of .NET Core.");
#elif NETFRAMEWORK
    Console.WriteLine("This is the legacy .NET Framework.");
#else
    Console.WriteLine("This is something else.");
#endif

Да, я думаю, что это имеет смысл (для вашего конкретного случая, поскольку изменения относительно незначительны), хотя очевидно, что подобные вещи могут быстро выйти из-под контроля.

ИМХО, наиболее логичным способом было бы создать различные конфигурации решений / проектов для каждой версии, а затем определить собственный символ (скажем, NET40) в ваших конфигурациях 4.0, затем используйте это с #if, Я не уверен, что конфигурации позволят вам изменить версию во время выполнения (это, очевидно, было бы идеальным решением), но в худшем случае вам придется менять версию вручную.

РЕДАКТИРОВАТЬ: Я только что увидел ответ, связанный с ответом Джошуа, и это кажется более обтекаемым решением, но я все равно оставлю это здесь, так как он, строго говоря, отвечает на вопрос.

Вы можете подготовить свой код для.NET 4.0 и написать аналогичный код для.NET 3.5 на основе определения инфраструктуры.

#if NOT_RUNNING_ON_4
public static class GuidExtensions
{
   public static bool TryParse(this string s, out Guid result)
   {
       if (s.IsNullOrEmpty())
           return null;
       try
       {
          return new Guid(s);
       }
       catch (FormatException)
       {
          return null;
      }
   }
}
#else
    #error switch parsing to .NET 4.0
#endif

И поместите свою линию в ваш *.csproj

<DefineConstants Condition=" '$(TargetFrameworkVersion)' != 'v4.0' ">NOT_RUNNING_ON_4</DefineConstants>
Другие вопросы по тегам