Можно ли сделать директиву препроцессора зависимой от версии платформы.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 или старше, он может вызвать свою собственную внутреннюю реализацию.
- Эта идея имеет смысл?
- Если это имеет смысл, какой самый логичный способ сделать это? Я думаю, я просто предполагаю, что директива препроцессора будет иметь смысл, так как вызов
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>