День 2150. #ЧтоНовенького #NET10
Заглядываем в .NET 10
9я версия .NET вышла всего месяц назад, а уже появляются предложения того, что может появиться через год в юбилейной 10й версии.
1. «Левое объединение» в LINQ
В LINQ есть оператор Join, который чаще всего в SQL преобразуется во что-то вроде INNER JOIN. В LINQ нет встроенного оператора для LEFT JOIN, но вы можете достичь того же результата, используя комбинацию GroupJoin, SelectMany и DefaultIfEmpty:
Имейте в виду, если вы хотите объединить несколько столбцов, они должны иметь одинаковые имена и типы данных.
Теперь появилось предложение добавить оператор LeftJoin в .NET 10. Тогда запрос выше будет выглядеть так:
На данный момент неясно, будет ли в синтаксисе запроса новое ключевое слово, представляющее оператор LeftJoin. Но вполне вероятно, что оно будет добавлено в синтаксис методов.
2. Неблокирующий старт фоновых сервисов
Небольшое изменение в способе запуска BackgroundService в .NET 10. Вы могли заметить, что запуск фонового сервиса блокирует запуск приложения до тех пор, пока не будет запущен сервис. Это происходит из-за того, что метод StartAsync вызывается синхронно в реализации IHostedService. Вы можете использовать следующий трюк, чтобы обойти это:
Или обернуть всё в Task.Run. Но это не очень хорошо и нелегко обнаружить. В .NET 10 это поведение будет заменено на реально асинхронное, и приложение не будет блокироваться при запуске.
3. Новый компаратор строк
Представьте, что вы хотите отсортировать следующие две строки: Windows 10 и Windows 7. Если рассматривать их исключительно как строки, Windows 10 будет идти перед Windows 7, потому что символ 1 идет перед 7. Но есть контексты, в которых вам нужно рассматривать некоторую часть строки как число и сортировать строки соответствующим образом. Вот тут и пригодится новый StringComparer. Он позволит вам сортировать строки как числа, поэтому Windows 10 будет идти после Windows 7.
Другой пример, упомянутый в предложении, - сортировка IP адресов.
Источники:
- https://steven-giesel.com/blogPost/82ebfd51-23c0-44b7-9602-628d1aba5f3c/linq-might-get-a-left-join-operator-in-net-10
- https://steven-giesel.com/blogPost/3a8c29a3-750a-40f0-aa43-c236b855813e/some-news-about-net-10-backgroundservices-and-new-string-comparer
Заглядываем в .NET 10
9я версия .NET вышла всего месяц назад, а уже появляются предложения того, что может появиться через год в юбилейной 10й версии.
1. «Левое объединение» в LINQ
В LINQ есть оператор Join, который чаще всего в SQL преобразуется во что-то вроде INNER JOIN. В LINQ нет встроенного оператора для LEFT JOIN, но вы можете достичь того же результата, используя комбинацию GroupJoin, SelectMany и DefaultIfEmpty:
var query =
_dbctx.Table1
.GroupJoin(
_dbctx.Table2,
t1 => t1.T2Id,
t2 => t2.Id,
(t1, t2) => new { t1, t2 }
)
.SelectMany(
t => t.t2.DefaultIfEmpty(),
(t, t2) => new { t1 = @t.t1, t2 }
);
Имейте в виду, если вы хотите объединить несколько столбцов, они должны иметь одинаковые имена и типы данных.
Теперь появилось предложение добавить оператор LeftJoin в .NET 10. Тогда запрос выше будет выглядеть так:
var query = _dbctx.Table1
.LeftJoin(
_dbctx.Table2,
t1 => t1.T2Id,
t2 => t2.Id,
(t1, t2) => new { t1, t2 }
);
На данный момент неясно, будет ли в синтаксисе запроса новое ключевое слово, представляющее оператор LeftJoin. Но вполне вероятно, что оно будет добавлено в синтаксис методов.
2. Неблокирующий старт фоновых сервисов
Небольшое изменение в способе запуска BackgroundService в .NET 10. Вы могли заметить, что запуск фонового сервиса блокирует запуск приложения до тех пор, пока не будет запущен сервис. Это происходит из-за того, что метод StartAsync вызывается синхронно в реализации IHostedService. Вы можете использовать следующий трюк, чтобы обойти это:
public class MyService : BackgroundService
{
private IHostApplicationLifetime _lt;
public MyService(IHostApplicationLifetime lt)
{
_lt = lt;
}
protected override async Task
ExecuteAsync(CancellationToken ct)
{
await Task.Yield();
// Вся работа здесь
}
}
Или обернуть всё в Task.Run. Но это не очень хорошо и нелегко обнаружить. В .NET 10 это поведение будет заменено на реально асинхронное, и приложение не будет блокироваться при запуске.
3. Новый компаратор строк
Представьте, что вы хотите отсортировать следующие две строки: Windows 10 и Windows 7. Если рассматривать их исключительно как строки, Windows 10 будет идти перед Windows 7, потому что символ 1 идет перед 7. Но есть контексты, в которых вам нужно рассматривать некоторую часть строки как число и сортировать строки соответствующим образом. Вот тут и пригодится новый StringComparer. Он позволит вам сортировать строки как числа, поэтому Windows 10 будет идти после Windows 7.
var list = new List<string> { "Windows 10", "Windows 7" };
list.Sort(StringComparer.NumericOrdering);
Другой пример, упомянутый в предложении, - сортировка IP адресов.
Источники:
- https://steven-giesel.com/blogPost/82ebfd51-23c0-44b7-9602-628d1aba5f3c/linq-might-get-a-left-join-operator-in-net-10
- https://steven-giesel.com/blogPost/3a8c29a3-750a-40f0-aa43-c236b855813e/some-news-about-net-10-backgroundservices-and-new-string-comparer
👍29
День 2224. #ЧтоНовенького #NET10
Новые Функции в С#14
Выпущен первый превью .NET 10. Давайте взглянем на парочку первых потенциальных дополнений к языку.
1. Null-условное присваивание
Основная проблема, которую здесь пытаются решить, выглядит примерно так: представьте, что у вас есть переменная, которая может быть null. Если это не так, вы хотите присвоить значение её свойству. Вот как это делается сейчас:
Предложено упростить код выше до следующего:
Таким образом, если myObj не null, будет сделано присваивание свойству Property. В противном случае – нет. По сути, это очередной синтаксический сахар, который может приводить к «прекрасным» присвоениям вроде такого:
2. Аллокация массивов типов значений на стеке
В .NET 9 JIT уже получил возможность аллоцировать объекты на стеке, когда объект гарантированно не переживёт свой родительский метод (например, когда объект – переменная внутри метода). Аллокация на стеке не только уменьшает количество объектов, которые должен отслеживать GC, но и открывает другие возможности оптимизации: например, после аллокации объекта на стеке JIT может рассмотреть возможность полной его замены на скалярные значения.
В .NET 10 JIT теперь будет выделять в стеке и небольшие массивы фиксированного размера, состоящие из типов значений, не содержащих ссылок, на условиях, описанных выше (существование внутри метода). Рассмотрим следующий пример:
Поскольку JIT знает, что numbers — это массив, создаваемый во время компиляции и состоящий всего из трёх целых чисел, а также он не переживёт метод Sum, то JIT аллоцирует его на стеке.
В следующих превью версиях среди других улучшений аллокаций на стеке планируется расширить эту возможность на массивы ссылочных типов.
Источники:
- https://steven-giesel.com/blogPost/b6d22649-7fba-488b-b252-31efdb3686c5/c-14-nullconditional-assignment
- https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/runtime.md#stack-allocation-of-arrays-of-value-types
Новые Функции в С#14
Выпущен первый превью .NET 10. Давайте взглянем на парочку первых потенциальных дополнений к языку.
1. Null-условное присваивание
Основная проблема, которую здесь пытаются решить, выглядит примерно так: представьте, что у вас есть переменная, которая может быть null. Если это не так, вы хотите присвоить значение её свойству. Вот как это делается сейчас:
MyObject? myObj = GetMyObjectOrNull();
if (myObj is not null)
{
myObj.Property = 100;
}
Предложено упростить код выше до следующего:
MyObject? myObj = GetMyObjectOrNull ();
myObj?.Property = 100;
Таким образом, если myObj не null, будет сделано присваивание свойству Property. В противном случае – нет. По сути, это очередной синтаксический сахар, который может приводить к «прекрасным» присвоениям вроде такого:
MyDeeplyNestedObj? m = FromSomewhere();
m?.A?.B?.C?.D = "Foo Bar";
2. Аллокация массивов типов значений на стеке
В .NET 9 JIT уже получил возможность аллоцировать объекты на стеке, когда объект гарантированно не переживёт свой родительский метод (например, когда объект – переменная внутри метода). Аллокация на стеке не только уменьшает количество объектов, которые должен отслеживать GC, но и открывает другие возможности оптимизации: например, после аллокации объекта на стеке JIT может рассмотреть возможность полной его замены на скалярные значения.
В .NET 10 JIT теперь будет выделять в стеке и небольшие массивы фиксированного размера, состоящие из типов значений, не содержащих ссылок, на условиях, описанных выше (существование внутри метода). Рассмотрим следующий пример:
static void Sum()
{
int[] numbers = {1, 2, 3};
int sum = 0;
for (int i = 0; i < numbers.Length; i++)
{
sum += numbers[i];
}
Console.WriteLine(sum);
}
Поскольку JIT знает, что numbers — это массив, создаваемый во время компиляции и состоящий всего из трёх целых чисел, а также он не переживёт метод Sum, то JIT аллоцирует его на стеке.
В следующих превью версиях среди других улучшений аллокаций на стеке планируется расширить эту возможность на массивы ссылочных типов.
Источники:
- https://steven-giesel.com/blogPost/b6d22649-7fba-488b-b252-31efdb3686c5/c-14-nullconditional-assignment
- https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/runtime.md#stack-allocation-of-arrays-of-value-types
1👍37
День 2236. #ЧтоНовенького #NET10
System.Linq.Async Стал Частью .NET 10
IAsyncEnumerable — интерфейс, который был представлен во времена netcoreapp3.1. Хотя он и похож на IEnumerable (пусть и асинхронный), он никогда не имел таких возможностей, как его синхронный аналог. До .NET 10. Теперь у нас есть некоторое соответствие функций между ними.
Что такое IAsyncEnumerable?
Представьте, что у вас есть коллекция чего-то. В IEnumerable<T> это может быть Enumerable.Range(0, 10_000), что сгенерирует 10000 элементов. Но что, если генерация каждого элемента асинхронна?
Task<IEnumerable<T>> нам поможет? Не совсем. Придётся сначала ждать генерации всех элементов, а потом их обрабатывать.
А как насчет IEnumerable<Task<T>>? Семантика намекает, что у нас есть коллекция, в которой каждый элемент должен быть ожидаем. Но вам придётся заботиться о каждом элементе самостоятельно. Т.е. метод возвращает перечисление из задач, а вам решать, как обрабатывать эти задачи. Вот тут и поможет IAsyncEnumerable. По сути он похож на IEnumerable<Task<T>>, но упрощает обработку результатов. См. подробнее про асинхронные коллекции.
AsyncEnumerable
AsyncEnumerable, как и его синхронная версия Enumerable, определяет все полезные расширения (вроде Select, Where и т. д.) для типа IAsyncEnumerable. Поэтому вы можете написать такой код:
Или:
Т.е. материализующая часть имеет суффикс Async. В целом, это может помочь более широкому использованию IAsyncEnumerable, хотя он в любом случае остаётся довольно нишевым. Вот оригинальное предложение на GitHub. А полный список изменений тут.
System.Linq.Async
Этот API не новый, а взят отсюда. API доступен через NuGet-пакет System.Linq.Async. Хотя пакет по-прежнему действует для всего ниже .NET 10, нет смысла использовать его начиная с 10й версии. Поэтому пакет можно полностью удалить. API, судя по всему, идентичен. Если у вас этот пакет используется в качестве транзитивной зависимости, можно исключить библиотеку вот так:
Источник: https://steven-giesel.com/blogPost/e40aaedc-9e56-491f-9fe5-3bb0b162ae94/systemlinqasync-is-part-of-net-10-linq-for-iasyncenumerable
System.Linq.Async Стал Частью .NET 10
IAsyncEnumerable — интерфейс, который был представлен во времена netcoreapp3.1. Хотя он и похож на IEnumerable (пусть и асинхронный), он никогда не имел таких возможностей, как его синхронный аналог. До .NET 10. Теперь у нас есть некоторое соответствие функций между ними.
Что такое IAsyncEnumerable?
Представьте, что у вас есть коллекция чего-то. В IEnumerable<T> это может быть Enumerable.Range(0, 10_000), что сгенерирует 10000 элементов. Но что, если генерация каждого элемента асинхронна?
Task<IEnumerable<T>> нам поможет? Не совсем. Придётся сначала ждать генерации всех элементов, а потом их обрабатывать.
А как насчет IEnumerable<Task<T>>? Семантика намекает, что у нас есть коллекция, в которой каждый элемент должен быть ожидаем. Но вам придётся заботиться о каждом элементе самостоятельно. Т.е. метод возвращает перечисление из задач, а вам решать, как обрабатывать эти задачи. Вот тут и поможет IAsyncEnumerable. По сути он похож на IEnumerable<Task<T>>, но упрощает обработку результатов. См. подробнее про асинхронные коллекции.
AsyncEnumerable
AsyncEnumerable, как и его синхронная версия Enumerable, определяет все полезные расширения (вроде Select, Where и т. д.) для типа IAsyncEnumerable. Поэтому вы можете написать такой код:
IAsyncEnumerable<MyObject> items = GetItems();
var filtered = await items
.Where(x => x.IsEnabled)
.ToListAsync(cancellationToken: token);
Или:
var avg = await items
.Select(s => s.SomeNumber)
.AverageAsync(cancellationToken);
Т.е. материализующая часть имеет суффикс Async. В целом, это может помочь более широкому использованию IAsyncEnumerable, хотя он в любом случае остаётся довольно нишевым. Вот оригинальное предложение на GitHub. А полный список изменений тут.
System.Linq.Async
Этот API не новый, а взят отсюда. API доступен через NuGet-пакет System.Linq.Async. Хотя пакет по-прежнему действует для всего ниже .NET 10, нет смысла использовать его начиная с 10й версии. Поэтому пакет можно полностью удалить. API, судя по всему, идентичен. Если у вас этот пакет используется в качестве транзитивной зависимости, можно исключить библиотеку вот так:
<PackageReference Include="System.Linq.Async" Version="6.0.1">
<ExcludeAssets>all</ExcludeAssets>
</PackageReference>
Источник: https://steven-giesel.com/blogPost/e40aaedc-9e56-491f-9fe5-3bb0b162ae94/systemlinqasync-is-part-of-net-10-linq-for-iasyncenumerable
👍25
День 2253. #ЧтоНовенького #NET10
Новинки Превью 2 ASP.NET Core 10
В последнем выпуске ASP.NET Core 10 Preview 2 представлены несколько улучшений в Blazor, в создании документации OpenAPI и в инструментах разработчика. Большинство изменений присланы контрибьюторами и основаны на обратной связи от разработчиков.
1. Переработана навигация в Blazor
При использовании NavigateTo для навигации по той же странице (например, при изменении только строки запроса) браузер больше не будет принудительно прокручивать страницу вверх. В предыдущих версиях разработчикам приходилось вручную обходить это поведение.
Компонент NavLink теперь по умолчанию игнорирует строки запроса и фрагменты (часть URL после #) при сопоставлении с помощью NavLinkMatch.All. Это означает, что ссылка будет активна, даже если строки запроса или фрагменты в URL изменятся. В AppContext есть переключатель, который позволит вернуться к предыдущему поведению, если вам это необходимо. Для кастомного поведения сопоставления NavLink теперь предоставляет переопределяемый метод ShouldMatch.
Визуализация повторного подключения, когда клиент теряет WebSocket-соединение с сервером, обновилась в шаблоне проекта, и представляет новый компонент ReconnectModal, который разделяет CSS и JavaScript для более строгого соответствия политике безопасности контента (CSP). Настраиваемое событие components-reconnect-state-changed обеспечивает более детальный контроль над состояниями подключения, включая новую фазу retrying (повторной попытки).
2. Изменения в OpenAPI
Разработчики API получат встроенную поддержку для автоматического преобразования описаний <summary> в исходном коде в документы OpenAPI. Для этого нужно добавить в файл проекта следующую строку:
Тогда во время компиляции генератор исходного кода соберёт комментарии и создаст документ OpenAPI. Однако в конечных точках минимальных API придётся использовать именованные методы, а не лямбды, чтобы использовать эту функцию. Например, вместо
использовать вызов метода
и определить метод Hello с описанием
3. Прочие изменения
При использовании атрибута
Здесь при отсутствии значения в форме DueDate будет установлено в null.
Новые метрики аутентификации для панели управления Aspire отслеживают события входа/выхода и попытки авторизации, а телеметрия продолжительности запроса помогает выявлять узкие места производительности.
Источники:
- https://www.infoq.com/news/2025/03/aspnet-core-10-preview2
- https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview2/aspnetcore.md
Новинки Превью 2 ASP.NET Core 10
В последнем выпуске ASP.NET Core 10 Preview 2 представлены несколько улучшений в Blazor, в создании документации OpenAPI и в инструментах разработчика. Большинство изменений присланы контрибьюторами и основаны на обратной связи от разработчиков.
1. Переработана навигация в Blazor
При использовании NavigateTo для навигации по той же странице (например, при изменении только строки запроса) браузер больше не будет принудительно прокручивать страницу вверх. В предыдущих версиях разработчикам приходилось вручную обходить это поведение.
Компонент NavLink теперь по умолчанию игнорирует строки запроса и фрагменты (часть URL после #) при сопоставлении с помощью NavLinkMatch.All. Это означает, что ссылка будет активна, даже если строки запроса или фрагменты в URL изменятся. В AppContext есть переключатель, который позволит вернуться к предыдущему поведению, если вам это необходимо. Для кастомного поведения сопоставления NavLink теперь предоставляет переопределяемый метод ShouldMatch.
Визуализация повторного подключения, когда клиент теряет WebSocket-соединение с сервером, обновилась в шаблоне проекта, и представляет новый компонент ReconnectModal, который разделяет CSS и JavaScript для более строгого соответствия политике безопасности контента (CSP). Настраиваемое событие components-reconnect-state-changed обеспечивает более детальный контроль над состояниями подключения, включая новую фазу retrying (повторной попытки).
2. Изменения в OpenAPI
Разработчики API получат встроенную поддержку для автоматического преобразования описаний <summary> в исходном коде в документы OpenAPI. Для этого нужно добавить в файл проекта следующую строку:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
Тогда во время компиляции генератор исходного кода соберёт комментарии и создаст документ OpenAPI. Однако в конечных точках минимальных API придётся использовать именованные методы, а не лямбды, чтобы использовать эту функцию. Например, вместо
app.MapGet("/hello",
(string name) =>$"Hello, {name}!");
использовать вызов метода
app.MapGet("/hello", Hello);
и определить метод Hello с описанием
static partial class Program
{
/// <summary>
/// Отправляет приветствие.
/// </summary>
/// …
public static string Hello(string name)
{
return $"Hello, {name}!";
}
}
3. Прочие изменения
При использовании атрибута
[FromForm]
со сложным объектом в минимальных API пустые строки в теле формы теперь преобразуются в null, а не вызывают ошибку парсинга. Это поведение соответствует логике обработки форм, не принимающих сложные объекты, в минимальных API:app.MapPost("/todo", ([FromForm] Todo todo)
=> TypedResults.Ok(todo));
public record Todo(int Id, DateOnly? DueDate,
string Title, bool Completed);
Здесь при отсутствии значения в форме DueDate будет установлено в null.
Новые метрики аутентификации для панели управления Aspire отслеживают события входа/выхода и попытки авторизации, а телеметрия продолжительности запроса помогает выявлять узкие места производительности.
Источники:
- https://www.infoq.com/news/2025/03/aspnet-core-10-preview2
- https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview2/aspnetcore.md
👍15
День 2357. #ЧтоНовенького #NET10
Разбираем Возможности dotnet run app.cs. Начало
В этой серии подробно разберём новую функцию, появившуюся в .NET 10, для сборки и запуска одного C#-файла без необходимости предварительного создания проекта .csproj. Похоже, у неё пока нет окончательного названия. В некоторых источниках её называют однофайловым приложением (file-based app), иногда - «runfile».
Что это?
В .NET 10 добавлена возможность сохранить код в один файл .cs и запустить его, выполнив команду
См. представление новой функции здесь.
Доступные функции
Пока возможности относительно ограничены, но есть несколько точек расширения. Следующий пример демонстрирует простое хост-приложение Aspire без операций, реализованное в виде однофайлового приложения. Он ничего не делает, а просто демонстрирует все функции, доступные в .NET 10 превью 5:
Этот скрипт демонстрирует все новые директивы, доступные в режиме запуска однофайлового приложения.
1. Создание исполняемого файла с помощью шебанг
#! (шебанг) и представляет директиву для систем *nix, позволяющую запускать файл напрямую. См. подробнее.
2. Добавление ссылок на SDK
Возможно с помощью директивы #:sdk. Также, как видите, можно указать версию. Заметьте, что в превью 5 она указывается через пробел, но, возможно, синтаксис поменяется для соответствия синтаксису добавления NuGet-пакетов.
3. Добавление ссылок на NuGet-пакеты
Возможно с помощью директивы #:package. Версия указывается после @. Можно использовать подстановочный знак (*) для версий:
Подстановочный знак обычно выберет наивысшую версию пакета.
4. Обновление свойств MSBuild
#:property используется для определения свойств MSBuild для приложения. Можно добавить любые свойства, которые обычно определяются в <PropertyGroup> файла .csproj. Здесь синтаксис, скорее всего тоже изменится. Вместо пробела нужно будет использовать =.
5. Ссылки на проекты (скоро)
В .NET 10 превью 6 должна появиться возможность ссылаться на проекты с помощью директивы #:project
Возможность ссылаться на каталог проекта вместо полного пути к файлу .csproj — отличный способ уменьшить дублирование.
Продолжение следует…
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
Разбираем Возможности dotnet run app.cs. Начало
В этой серии подробно разберём новую функцию, появившуюся в .NET 10, для сборки и запуска одного C#-файла без необходимости предварительного создания проекта .csproj. Похоже, у неё пока нет окончательного названия. В некоторых источниках её называют однофайловым приложением (file-based app), иногда - «runfile».
Что это?
В .NET 10 добавлена возможность сохранить код в один файл .cs и запустить его, выполнив команду
dotnet run app.cs
См. представление новой функции здесь.
Доступные функции
Пока возможности относительно ограничены, но есть несколько точек расширения. Следующий пример демонстрирует простое хост-приложение Aspire без операций, реализованное в виде однофайлового приложения. Он ничего не делает, а просто демонстрирует все функции, доступные в .NET 10 превью 5:
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk
#:sdk Aspire.AppHost.Sdk 9.3.0
#:package Aspire.Hosting.AppHost@9.3.0
#:property UserSecretsId 2eec9746-c21a-4933-90af-c22431f35459
using Microsoft.Extensions.Configuration;
var builder = DistributedApplication.CreateBuilder(args);
builder.Configuration.AddInMemoryCollection(new Dictionary<string, string?>
{
{ "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL", "https://localhost:21049" },
{ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL", "https://localhost:22001" },
{ "ASPNETCORE_URLS", "https://localhost:17246" },
});
builder.Build().Run();
Этот скрипт демонстрирует все новые директивы, доступные в режиме запуска однофайлового приложения.
1. Создание исполняемого файла с помощью шебанг
#! (шебанг) и представляет директиву для систем *nix, позволяющую запускать файл напрямую. См. подробнее.
2. Добавление ссылок на SDK
Возможно с помощью директивы #:sdk. Также, как видите, можно указать версию. Заметьте, что в превью 5 она указывается через пробел, но, возможно, синтаксис поменяется для соответствия синтаксису добавления NuGet-пакетов.
3. Добавление ссылок на NuGet-пакеты
Возможно с помощью директивы #:package. Версия указывается после @. Можно использовать подстановочный знак (*) для версий:
#:package Aspire.Hosting.AppHost@*
#:package Aspire.Hosting.AppHost@9.*
#:package Aspire.Hosting.AppHost@9.3.*
Подстановочный знак обычно выберет наивысшую версию пакета.
4. Обновление свойств MSBuild
#:property используется для определения свойств MSBuild для приложения. Можно добавить любые свойства, которые обычно определяются в <PropertyGroup> файла .csproj. Здесь синтаксис, скорее всего тоже изменится. Вместо пробела нужно будет использовать =.
5. Ссылки на проекты (скоро)
В .NET 10 превью 6 должна появиться возможность ссылаться на проекты с помощью директивы #:project
#:project ../src/MyProject
#:project ../src/MyProject/MyProject.csproj
Возможность ссылаться на каталог проекта вместо полного пути к файлу .csproj — отличный способ уменьшить дублирование.
Продолжение следует…
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
👍7
День 2358. #ЧтоНовенького #NET10
Разбираем Возможности dotnet run app.cs. Продолжение
Начало
Зачем?
Прежде всего, команда .NET ясно дала понять, что это делается для того, чтобы сделать обучение новичков .NET максимально удобным. Во многих других языках, будь то Node.js или Python, например, есть однофайловый интерфейс, а теперь он есть и в .NET. Новичок теперь может начать просто с файла .cs, и постепенно вводить новые концепции.
Постепенно вы дойдёте до точки, когда будет иметь смысл создать проект, например, для объединения нескольких CS-файлов. Тогда можно просто преобразовать отдельный файл в проект, выполнив:
Выполнение этой команды на примере из предыдущего поста создаст файл проекта, который выглядит следующим образом:
Все добавленные директивы включены в проект, а также добавлены другие значения по умолчанию. Это очень плавный переход от файловых приложений к файлам проектов.
Кроме того, есть несколько сценариев, где избавление от необходимости в отдельном проекте (и соответствующем каталоге) имеет смысл. Например:
1. Сервисные скрипты. Раньше вы, вероятно, использовали бы bash или PowerShell, но теперь, если хотите, можете легко использовать C#.
2. Примеры. Многие библиотеки или фреймворки предлагают несколько примеров приложений для демонстрации функций, каждому из которых требуется отдельная папка и файл проекта. Теперь у вас может быть одна папка, где каждый CS-файл будет примером приложения.
Дополнительные функции
Также существуют различные файлы, которые однофайловое приложение будет неявно использовать, если они доступны. К ним относятся:
- global.json
- NuGet.config
- Directory.Build.props
- Directory.Build.targets
- Directory.Packages.props
- Directory.Build.rsp
- MSBuild.rsp
Пожалуй, самый полезный из этих файлов — Directory.Build.props, который, по сути, позволяет «улучшить» ваше однофайловое приложение, добавив всё, что вы обычно помещаете в файл .csproj. Это особенно полезно, если у вас, например, есть несколько однофайловых приложений в каталоге, и вы хотите задать свойство или добавить пакет для всех, не обновляя каждое из них.
Это всё немного абстрактно, но вы можете увидеть различные примеры подобных вещей в репозитории «runfile Playground» Дэмиана Эдвардса, посвящённом этой функции!
Окончание следует…
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
Разбираем Возможности dotnet run app.cs. Продолжение
Начало
Зачем?
Прежде всего, команда .NET ясно дала понять, что это делается для того, чтобы сделать обучение новичков .NET максимально удобным. Во многих других языках, будь то Node.js или Python, например, есть однофайловый интерфейс, а теперь он есть и в .NET. Новичок теперь может начать просто с файла .cs, и постепенно вводить новые концепции.
Постепенно вы дойдёте до точки, когда будет иметь смысл создать проект, например, для объединения нескольких CS-файлов. Тогда можно просто преобразовать отдельный файл в проект, выполнив:
dotnet project convert app.cs
Выполнение этой команды на примере из предыдущего поста создаст файл проекта, который выглядит следующим образом:
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.3.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<UserSecretsId>2eec9746-c21a-4933-90af-c22431f35459</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3." />
</ItemGroup>
</Project>
Все добавленные директивы включены в проект, а также добавлены другие значения по умолчанию. Это очень плавный переход от файловых приложений к файлам проектов.
Кроме того, есть несколько сценариев, где избавление от необходимости в отдельном проекте (и соответствующем каталоге) имеет смысл. Например:
1. Сервисные скрипты. Раньше вы, вероятно, использовали бы bash или PowerShell, но теперь, если хотите, можете легко использовать C#.
2. Примеры. Многие библиотеки или фреймворки предлагают несколько примеров приложений для демонстрации функций, каждому из которых требуется отдельная папка и файл проекта. Теперь у вас может быть одна папка, где каждый CS-файл будет примером приложения.
Дополнительные функции
Также существуют различные файлы, которые однофайловое приложение будет неявно использовать, если они доступны. К ним относятся:
- global.json
- NuGet.config
- Directory.Build.props
- Directory.Build.targets
- Directory.Packages.props
- Directory.Build.rsp
- MSBuild.rsp
Пожалуй, самый полезный из этих файлов — Directory.Build.props, который, по сути, позволяет «улучшить» ваше однофайловое приложение, добавив всё, что вы обычно помещаете в файл .csproj. Это особенно полезно, если у вас, например, есть несколько однофайловых приложений в каталоге, и вы хотите задать свойство или добавить пакет для всех, не обновляя каждое из них.
Это всё немного абстрактно, но вы можете увидеть различные примеры подобных вещей в репозитории «runfile Playground» Дэмиана Эдвардса, посвящённом этой функции!
Окончание следует…
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
👍5
День 2359. #ЧтоНовенького #NET10
Разбираем Возможности dotnet run app.cs. Окончание
Начало
Продолжение
Наконец, посмотрим, что ещё готовится для однофайловых приложений.
Нет гарантии, что описанные ниже функции попадут в финальную версию, но есть большие шансы на это, учитывая, что первые несколько функций уже объединены в ветку следующего превью.
1. Публикация однофайловых приложений
Одна из функций, которая должна появиться в превью 6, — это возможность публиковать однофайловые приложения с помощью:
При этом по умолчанию приложения будут публиковаться как приложения NativeAOT! Вы можете отключить это, добавив #:property PublishAot false, но, скорее всего, всё будет работать без проблем во многих сценариях, для которых предназначены однофайловые приложения.
2. Запуск через dotnet app.cs
Поддержка запуска однофайловых приложений без использования команды run, т.е. вы можете использовать
вместо
Одно из главных преимуществ этого подхода заключается в том, что он делает поддержку шебангов в Linux более надёжной. Например, если вы хотите использовать /usr/bin/env для поиска исполняемого файла dotnet, вместо того, чтобы предполагать, что он находится в /usr/bin/dotnet, раньше нужно было сделать что-то вроде этого:
К сожалению, из-за того, что здесь приходится предоставлять несколько аргументов ("dotnet run"), это может не работать в некоторых оболочках. Однако с новой поддержкой dotnet app.cs вы можете использовать более простой и широко поддерживаемый вариант:
3. Запуск C# напрямую из стандартного ввода
Недавно была добавлена поддержка конвейеризации C#-кода напрямую в dotnet run, что позволяет выполнять такие действия:
Это перенаправляет приложение Hello World прямо из консоли в dotnet run и запускает его. Классический случай, когда «так делать ни в коем случае нельзя, но люди постоянно это делают», — скачиваем код из сети через curl и запускаем его напрямую - теперь возможен:
Чего не будет?
1. Одна из важных функций, которая не появится в .NET 10, — это поддержка нескольких файлов. Изначально планировалось включить её, причём такие вещи, как «вложенные» файлы и подкаталоги, которые неявно включались в компиляцию. Вместо этого эта работа была перенесена на .NET 11, чтобы сосредоточиться на максимальном улучшении взаимодействия с одним файлом.
Вы можете косвенно получить поддержку нескольких файлов, используя Directory.Build.props и Directory.Build.targets, а также добавляя ссылки на файлы «вручную».
2. Поддержка отдельных файлов не появится в Visual Studio. Поддержка от Microsoft будет реализована только в Visual Studio Code (и, разумеется, в CLI).
3. На данном этапе поддержка отдельных файлов будет реализована только для файлов .cs, а не для файлов .vb или .fs. Команда разработчиков не исключает полностью эту возможность, но маловероятно, что Microsoft сами добавят такую поддержку.
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
Разбираем Возможности dotnet run app.cs. Окончание
Начало
Продолжение
Наконец, посмотрим, что ещё готовится для однофайловых приложений.
Нет гарантии, что описанные ниже функции попадут в финальную версию, но есть большие шансы на это, учитывая, что первые несколько функций уже объединены в ветку следующего превью.
1. Публикация однофайловых приложений
Одна из функций, которая должна появиться в превью 6, — это возможность публиковать однофайловые приложения с помощью:
dotnet publish app.cs
При этом по умолчанию приложения будут публиковаться как приложения NativeAOT! Вы можете отключить это, добавив #:property PublishAot false, но, скорее всего, всё будет работать без проблем во многих сценариях, для которых предназначены однофайловые приложения.
2. Запуск через dotnet app.cs
Поддержка запуска однофайловых приложений без использования команды run, т.е. вы можете использовать
dotnet app.cs
вместо
dotnet run app.cs
Одно из главных преимуществ этого подхода заключается в том, что он делает поддержку шебангов в Linux более надёжной. Например, если вы хотите использовать /usr/bin/env для поиска исполняемого файла dotnet, вместо того, чтобы предполагать, что он находится в /usr/bin/dotnet, раньше нужно было сделать что-то вроде этого:
#!/usr/bin/env dotnet run
К сожалению, из-за того, что здесь приходится предоставлять несколько аргументов ("dotnet run"), это может не работать в некоторых оболочках. Однако с новой поддержкой dotnet app.cs вы можете использовать более простой и широко поддерживаемый вариант:
#!/usr/bin/env dotnet
3. Запуск C# напрямую из стандартного ввода
Недавно была добавлена поддержка конвейеризации C#-кода напрямую в dotnet run, что позволяет выполнять такие действия:
> 'Console.WriteLine("Hello, World!");' | dotnet run -
Hello, World!
Это перенаправляет приложение Hello World прямо из консоли в dotnet run и запускает его. Классический случай, когда «так делать ни в коем случае нельзя, но люди постоянно это делают», — скачиваем код из сети через curl и запускаем его напрямую - теперь возможен:
> curl -S http://totally-safe-not-scary-at-all.com/ | dotnet run -
All your bases are belong to us!
Чего не будет?
1. Одна из важных функций, которая не появится в .NET 10, — это поддержка нескольких файлов. Изначально планировалось включить её, причём такие вещи, как «вложенные» файлы и подкаталоги, которые неявно включались в компиляцию. Вместо этого эта работа была перенесена на .NET 11, чтобы сосредоточиться на максимальном улучшении взаимодействия с одним файлом.
Вы можете косвенно получить поддержку нескольких файлов, используя Directory.Build.props и Directory.Build.targets, а также добавляя ссылки на файлы «вручную».
2. Поддержка отдельных файлов не появится в Visual Studio. Поддержка от Microsoft будет реализована только в Visual Studio Code (и, разумеется, в CLI).
3. На данном этапе поддержка отдельных файлов будет реализована только для файлов .cs, а не для файлов .vb или .fs. Команда разработчиков не исключает полностью эту возможность, но маловероятно, что Microsoft сами добавят такую поддержку.
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
👍6