Введение: Лабиринт .NET-библиотек
Если вы когда-нибудь создавали новый проект в Visual Studio или Rider, то наверняка видели два похожих, но сбивающих с толку шаблона: Class Library (.NET Core) и Class Library (.NET Standard). Возникает закономерный вопрос: «А в чем, собственно, разница? И что мне выбрать, чтобы потом не переписывать всё с нуля?».
Это не просто академический интерес. На Stack Overflow этот вопрос собрал тысячи просмотров, а путаница между этими двумя типами проектов — одна из самых частых ошибок новичков. В этой статье мы раз и навсегда разберемся в этой дилемме, посмотрим на реальные примеры кода на C# и выясним, какой тип библиотеки подходит именно для вашей задачи.
1. Краткий экскурс в историю: от .NET Framework до эпохи унификации
Чтобы понять разницу, нужно вспомнить, как развивалась платформа. Раньше был только .NET Framework — монолитная среда для Windows. Затем появился .NET Core — кроссплатформенная, легковесная версия. И тут возникла проблема: как написать библиотеку, которая работала бы и там, и там? Для этого придумали .NET Standard — формальную спецификацию API, которые гарантированно есть во всех реализациях .NET.
Однако с выходом .NET 5 (и далее .NET 6, 7, 8) Microsoft объединила платформы. Теперь есть единый базовый класс — .NET (ранее .NET Core). Это сильно изменило правила игры. Давайте разберем, что это значит для нас, разработчиков.
2. Что такое Class Library (.NET Standard)?
.NET Standard — это не runtime, а набор контрактов. Представьте, что это «универсальный переходник». Если вы создаете библиотеку, нацеленную на netstandard2.0, она сможет работать:
- В .NET Framework 4.6.1+
- В .NET Core 2.0+
- В .NET 5/6/7/8
- В Xamarin, Mono, Unity и даже в UWP
Это идеальный выбор, если вам нужно максимальное покрытие платформ. Вы пишете код один раз — и он работает везде, где поддерживается эта версия стандарта.
Пример кода для .NET Standard библиотеки
Создадим простую библиотеку для работы со строками, нацеленную на netstandard2.0:
// StringHelper.cs
using System;
using System.Text.RegularExpressions;
namespace MyStandardLibrary
{
public class StringHelper
{
/// <summary>
/// Удаляет все HTML-теги из строки.
/// </summary>
public static string StripHtmlTags(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
// Простой, но эффективный regex для удаления тегов
return Regex.Replace(input, "<.*?>", string.Empty);
}
/// <summary>
/// Переворачивает строку задом наперед.
/// </summary>
public static string ReverseString(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
char[] chars = input.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}
}
Обратите внимание: мы используем только базовые классы (System, System.Text.RegularExpressions), которые гарантированно есть во всех реализациях .NET Standard 2.0. Эта библиотека будет работать даже в проекте на .NET Framework 4.6.1, который Microsoft больше не развивает, но который до сих пор используется в корпоративном секторе.
3. Что такое Class Library (.NET Core / .NET)?
Когда вы выбираете .NET Core Class Library (или просто .NET Class Library, если у вас .NET 5+), вы привязываетесь к конкретной реализации платформы. В файле проекта (csproj) вы увидите что-то вроде <TargetFramework>net8.0</TargetFramework>.
Это дает вам доступ ко всем новейшим фишкам языка и API:
Span<T>иMemory<T>для высокопроизводительной работы с памятью.- Последние версии
C#(records, primary constructors, etc.). - Специфичные для ОС API (через условную компиляцию).
Но плата за это — потеря совместимости. Ваша библиотека не будет работать в старом .NET Framework или Xamarin без дополнительных телодвижений.
Пример кода для .NET 8 библиотеки
Давайте реализуем ту же задачу, но с использованием современных возможностей:
// StringHelper.cs
using System;
using System.Text.RegularExpressions;
namespace MyModernLibrary
{
public partial class StringHelper
{
/// <summary>
/// Удаляет HTML-теги с использованием Source Generator для Regex.
/// </summary>
[GeneratedRegex("<.*?>")]
private static partial Regex HtmlTagRegex();
public static string StripHtmlTags(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
return HtmlTagRegex().Replace(input, string.Empty);
}
/// <summary>
/// Переворачивает строку с использованием Span<T> (доступно только в .NET Core/.NET 5+).
/// </summary>
public static string ReverseString(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
// Используем Span для оптимизации производительности
Span<char> span = input.ToCharArray();
span.Reverse();
return new string(span);
}
}
}
Видите разницу? Мы использовали [GeneratedRegex] — атрибут, который компилирует регулярное выражение во время сборки (доступен в .NET 7+). Также мы применили Span<char> для более быстрой работы с памятью. Если вы попытаетесь подключить эту библиотеку к проекту на .NET Framework 4.8, компилятор выдаст ошибку — этих API там просто нет.
4. Ключевые различия: когда что использовать?
Давайте сведем всё в таблицу, чтобы было наглядно:
| Характеристика | .NET Standard Library | .NET Core / .NET Library |
|---|---|---|
| Совместимость | Максимальная (работает на старых и новых платформах) | Только .NET Core / .NET 5+ |
| Доступ к новым API | Ограничен версией стандарта | Полный доступ к последним API |
| Производительность | Базовая (без Span, без Source Generators) | Максимальная (все оптимизации платформы) |
Раз
БлогиРекомендаций по книгамЧитайте также
Тестирование в TypeScript: Unit, Integration и E2E тесты
|