.NET Разработчик
6.68K subscribers
451 photos
4 videos
14 files
2.17K links
Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1939. #ЗаметкиНаПолях
Функции C# и Целевая Платформа

Если вы заглянете на официальную страницу версий языка C#, то можно подумать, что существует сильная связь между целевой платформой и версией языка. И действительно, если вы не укажете версию языка явно в файле проекта, она будет выбрана на основе целевой платформы: C# 12 для .net8, C# 11 для .net7 и C# 7.3 для .NET Framework.

Фактическая же связь между версией языка и целевой платформой более тонкая. Есть три способа, как функция языка может быть связана с целевой платформой:
1. Просто работает
Некоторые функции работают сразу после установки версии языка. Установите нужную версию языка в блоке компиляции файла проекта
<LangVersion>12.0</LangVersion>

и новая функция будет работать независимо от целевой платформы.

2. Требуется специальное определение типа
Требует, чтобы компилятор обнаруживал специальные типы. Специальные типы добавляются в основной выпуск .net, соответствующий конкретной версии C#, но вы можете добавить их в свою компиляцию вручную, чтобы эти функции заработали. Компилятору не важно, откуда берётся определение типа: из целевой платформы, из NuGet-пакета или просто является частью проекта.
Например, следующая запись с init-сеттером и обязательным свойством:
public record class MyRecord
{
public int X { get; init; }
public required int Y { get; set; }
}

доступна в проекте netstandard2.0 или net472 при добавлении в проект следующего кода:
namespace System.Runtime.CompilerServices
{
// для init-сеттера
internal class IsExternalInit { }
// для обязательного свойства
internal class RequiredMemberAttribute : System.Attribute { }
internal sealed class CompilerFeatureRequiredAttribute(string featureName) : System.Attribute
{
public string FeatureName { get; set; } = featureName;
}
}
// для обязательного свойства
namespace System.Diagnostics.CodeAnalysis
{
internal class SetsRequiredMembersAttribute : System.Attribute { }
}

Чаще всего компилятор сообщит вам, какого типа или члена типа ему не хватает для успешной компиляции.

3. Зависит от времени выполнения
Лишь небольшая часть новых возможностей языка требует поддержки среды исполнения. Это, например, реализации интерфейсов по умолчанию, встроенные массивы или ref-поля. Такие функции не будут компилироваться, если целевая платформа их не поддерживает. В этом случае компилятор сообщит, что целевая среда выполнения не поддерживает эту функцию.

Трюк с InternalsVisisbleTo
Существует проблема с показанным ранее решением для 2го варианта. Допустим, у вас есть MyProject.csproj, ориентированный на netstandard2.0, и MyProject.Tests.csproj, ориентированный на net8.0 с InternalVisibleTo("MyProject.Tests") внутри MyProject.csproj для доступа к приватным классам проекта из тестов.

В этом случае вы не сможете скомпилировать MyProject.Tests.csproj с ошибкой о повторяющемся определении члена, поскольку тип IsExternalInit будет доступен из двух мест — из MyProject.csproj и из библиотеки времени выполнения .net8.0.

Решение довольно простое: используйте несколько целевых сред выполнения в проекте MyProject.csproj, например:
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>


Источник: https://sergeyteplyakov.github.io/Blog/c%23/2024/03/06/