Vývoj knihoven pomocí .NET CLI
Tento článek popisuje, jak psát knihovny pro .NET pomocí rozhraní příkazového řádku .NET. Rozhraní příkazového řádku poskytuje efektivní a nízké prostředí, které funguje v jakémkoli podporovaném operačním systému. Knihovny můžete vytvářet i v sadě Visual Studio a pokud je to vaše preferované prostředí , projděte si průvodce sadou Visual Studio.
Požadavky
Na svém počítači potřebujete nainstalovanou sadu .NET SDK .
V částech tohoto dokumentu, které se zabývají verzemi rozhraní .NET Framework, potřebujete rozhraní .NET Framework nainstalované na počítači s Windows.
Kromě toho, pokud chcete podporovat starší cíle rozhraní .NET Framework, musíte nainstalovat cílové balíčky nebo sady developer pack ze stránky pro stahování rozhraní .NET Framework. Projděte si tuto tabulku:
Verze rozhraní .NET Framework | Co stáhnout |
---|---|
4.6.1 | Sada cílení rozhraní .NET Framework 4.6.1 |
4.6 | Balíček cílení rozhraní .NET Framework 4.6 |
4.5.2 | Sada .NET Framework 4.5.2 Developer Pack |
4.5.1 | .NET Framework 4.5.1 Developer Pack |
4.5 | Sada Windows SDK pro aplikace pro Windows 8 |
4.0 | Windows SDK pro Windows 7 a .NET Framework 4 |
2.0, 3.0 a 3.5 | .NET Framework 3.5 SP1 Runtime (nebo verze Windows 8 nebo novější) |
Jak cílit na .NET 5 nebo .NET Standard
Cílovou architekturu projektu můžete řídit jeho přidáním do souboru projektu (.csproj nebo .fsproj). Pokyny k výběru mezi cílením na .NET 5 nebo .NET Standard najdete v tématech .NET 5+ a .NET Standard.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
Pokud chcete cílit na rozhraní .NET Framework verze 4.0 nebo nižší, nebo chcete použít rozhraní API dostupné v rozhraní .NET Framework, ale ne v rozhraní .NET Standard (například), přečtěte si následující části a zjistěte, System.Drawing
jak provést více cílů.
Jak cílit na rozhraní .NET Framework
Poznámka:
Tyto pokyny předpokládají, že máte na počítači nainstalované rozhraní .NET Framework. Informace o instalaci závislostí najdete v části Požadavky .
Mějte na paměti, že některé zde použité verze rozhraní .NET Framework už nejsou podporované. Nejčastější dotazy k nepodporovaným verzím najdete v zásadách životního cyklu podpory rozhraní .NET Framework.
Pokud chcete dosáhnout maximálního počtu vývojářů a projektů, použijte jako cíl směrného plánu rozhraní .NET Framework 4.0. Pokud chcete cílit na rozhraní .NET Framework, začněte správným monikerem cílového rozhraní (TFM), který odpovídá verzi rozhraní .NET Framework, kterou chcete podporovat.
Verze rozhraní .NET Framework | TFM |
---|---|
.NET Framework 2,0 | net20 |
.NET Framework 3.0 | net30 |
.NET Framework 3.5 | net35 |
.NET Framework 4.0 | net40 |
.NET Framework 4.5 | net45 |
.NET Framework 4.5.1 | net451 |
.NET Framework 4.5.2 | net452 |
.NET Framework 4.6 | net46 |
.NET Framework 4.6.1 | net461 |
.NET Framework 4.6.2 | net462 |
.NET Framework 4.7 | net47 |
.NET Framework 4.8 | net48 |
Tento TFM pak vložíte do TargetFramework
části souboru projektu. Tady je příklad, jak byste napsali knihovnu, která cílí na rozhraní .NET Framework 4.0:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
</Project>
A to je vše! I když je tento kompilovaný pouze pro rozhraní .NET Framework 4, můžete knihovnu použít v novějších verzích rozhraní .NET Framework.
Postup cílení na více verzí
Poznámka:
Následující pokyny předpokládají, že máte na počítači nainstalovanou rozhraní .NET Framework. V části Požadavky se dozvíte, ze kterých závislostí je potřeba nainstalovat a odkud je stáhnout.
Možná budete muset cílit na starší verze rozhraní .NET Framework, pokud váš projekt podporuje rozhraní .NET Framework i .NET. Pokud v tomto scénáři chcete pro novější cíle použít novější rozhraní API a jazykové konstrukty, použijte #if
ve svém kódu direktivy. Možná budete také muset přidat různé balíčky a závislosti pro každou platformu, na kterou cílíte, aby zahrnovala různá rozhraní API potřebná pro každý případ.
Řekněme například, že máte knihovnu, která provádí síťové operace přes protokol HTTP. Pro .NET Standard a rozhraní .NET Framework verze 4.5 nebo vyšší můžete použít HttpClient
třídu z System.Net.Http
oboru názvů. Starší verze rozhraní .NET Framework však nemají HttpClient
třídu, takže byste mohli místo toho použít WebClient
třídu z System.Net
oboru názvů.
Soubor projektu může vypadat takto:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net40;net45</TargetFrameworks>
</PropertyGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.0 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System.Net" />
</ItemGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.5 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.Net.Http" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
</Project>
Tady si všimnete tří hlavních změn:
- Uzel
TargetFramework
se nahradilTargetFrameworks
a uvnitř jsou vyjádřeny tři TFM. - Pro načtení cíle v jednom odkazu rozhraní .NET Framework existuje
<ItemGroup>
uzelnet40
. - Cílový pulling má
<ItemGroup>
uzelnet45
ve dvou odkazech rozhraní .NET Framework.
Symboly preprocesoru
Systém sestavení si uvědomuje následující symboly preprocesoru používané ve #if
direktivách:
Cílové architektury | Symboly | Další symboly (k dispozici v sadách .NET 5+ SDK) |
Symboly platformy (k dispozici pouze při zadání TFM specifického pro operační systém) |
---|---|---|---|
.NET Framework | NETFRAMEWORK , NET481 , , , NET471 NET47 NET45 NET40 NET472 NET461 NET35 NET462 NET46 NET452 NET451 NET48 NET20 |
NET48_OR_GREATER , NET472_OR_GREATER , , NET471_OR_GREATER , NET462_OR_GREATER NET47_OR_GREATER , NET461_OR_GREATER NET40_OR_GREATER NET452_OR_GREATER NET46_OR_GREATER NET451_OR_GREATER NET45_OR_GREATER , NET35_OR_GREATER NET20_OR_GREATER |
|
.NET Standard | NETSTANDARD , NETSTANDARD2_1 , , NETSTANDARD2_0 , NETSTANDARD1_5 NETSTANDARD1_6 , NETSTANDARD1_4 NETSTANDARD1_3 NETSTANDARD1_2 , , NETSTANDARD1_1 NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER , NETSTANDARD2_0_OR_GREATER , , NETSTANDARD1_5_OR_GREATER NETSTANDARD1_3_OR_GREATER NETSTANDARD1_2_OR_GREATER NETSTANDARD1_6_OR_GREATER NETSTANDARD1_4_OR_GREATER , , NETSTANDARD1_1_OR_GREATER NETSTANDARD1_0_OR_GREATER |
|
.NET 5+ (a .NET Core) | NET , NET9_0 , , NET8_0 , NET6_0 NET5_0 , NETCOREAPP2_0 NETCOREAPP1_1 NET7_0 NETCOREAPP NETCOREAPP3_1 NETCOREAPP3_0 NETCOREAPP2_2 NETCOREAPP2_1 NETCOREAPP1_0 |
NET8_0_OR_GREATER , NET7_0_OR_GREATER , , NET6_0_OR_GREATER , NETCOREAPP3_1_OR_GREATER NETCOREAPP2_0_OR_GREATER NET5_0_OR_GREATER NETCOREAPP3_0_OR_GREATER NETCOREAPP2_2_OR_GREATER NETCOREAPP2_1_OR_GREATER , NETCOREAPP1_1_OR_GREATER NETCOREAPP1_0_OR_GREATER |
ANDROID , BROWSER , IOS , , MACOS MACCATALYST , TVOS , , WINDOWS [OS][version] (například IOS15_1 ),[OS][version]_OR_GREATER (například IOS15_1_OR_GREATER ) |
Poznámka:
- Symboly bez verzí se definují bez ohledu na verzi, na kterou cílíte.
- Symboly specifické pro verzi jsou definované jenom pro verzi, na kterou cílíte.
- Symboly
<framework>_OR_GREATER
jsou definované pro verzi, na kterou cílíte, a všechny předchozí verze. Pokud například cílíte na rozhraní .NET Framework 2.0, jsou definovány následující symboly:NET20
,NET20_OR_GREATER
,NET11_OR_GREATER
aNET10_OR_GREATER
. - Symboly
NETSTANDARD<x>_<y>_OR_GREATER
jsou definovány pouze pro cíle .NET Standard, a ne pro cíle, které implementují .NET Standard, jako jsou .NET Core a .NET Framework. - Liší se od monikers cílové architektury (TFMs) používané vlastností MSBuild
TargetFramework
a NuGet.
Tady je příklad použití podmíněné kompilace podle cíle:
using System;
using System.Text.RegularExpressions;
#if NET40
// This only compiles for the .NET Framework 4 targets
using System.Net;
#else
// This compiles for all other targets
using System.Net.Http;
using System.Threading.Tasks;
#endif
namespace MultitargetLib
{
public class Library
{
#if NET40
private readonly WebClient _client = new WebClient();
private readonly object _locker = new object();
#else
private readonly HttpClient _client = new HttpClient();
#endif
#if NET40
// .NET Framework 4.0 does not have async/await
public string GetDotNetCount()
{
string url = "https://www.dotnetfoundation.org/";
var uri = new Uri(url);
string result = "";
// Lock here to provide thread-safety.
lock(_locker)
{
result = _client.DownloadString(uri);
}
int dotNetCount = Regex.Matches(result, ".NET").Count;
return $"Dotnet Foundation mentions .NET {dotNetCount} times!";
}
#else
// .NET Framework 4.5+ can use async/await!
public async Task<string> GetDotNetCountAsync()
{
string url = "https://www.dotnetfoundation.org/";
// HttpClient is thread-safe, so no need to explicitly lock here
var result = await _client.GetStringAsync(url);
int dotNetCount = Regex.Matches(result, ".NET").Count;
return $"dotnetfoundation.org mentions .NET {dotNetCount} times in its HTML!";
}
#endif
}
}
Pokud tento projekt sestavíte pomocí dotnet build
, všimnete si tří adresářů ve bin/
složce:
net40/
net45/
netstandard2.0/
Každý z těchto souborů obsahuje .dll
soubory pro každý cíl.
Testování knihoven v .NET
Je důležité, abyste mohli testovat na různých platformách. Můžete použít buď xUnit , nebo MSTest out of the box. Oba jsou dokonale vhodné pro testování jednotek vaší knihovny v .NET. Způsob nastavení řešení s testovacími projekty bude záviset na struktuře vašeho řešení. Následující příklad předpokládá, že testovací a zdrojové adresáře žijí ve stejném adresáři nejvyšší úrovně.
Poznámka:
K tomu se používají některé příkazy rozhraní příkazového řádku .NET. Další informace najdete v tématu dotnet new a dotnet sln .
Nastavte řešení. Můžete to udělat pomocí následujících příkazů:
mkdir SolutionWithSrcAndTest cd SolutionWithSrcAndTest dotnet new sln dotnet new classlib -o MyProject dotnet new xunit -o MyProject.Test dotnet sln add MyProject/MyProject.csproj dotnet sln add MyProject.Test/MyProject.Test.csproj
Tím vytvoříte projekty a propojíte je v řešení.
SolutionWithSrcAndTest
Adresář by měl vypadat takto:/SolutionWithSrcAndTest |__SolutionWithSrcAndTest.sln |__MyProject/ |__MyProject.Test/
Přejděte do adresáře testovacího projektu a přidejte odkaz na
MyProject.Test
zMyProject
.cd MyProject.Test dotnet add reference ../MyProject/MyProject.csproj
Obnovení balíčků a projektů sestavení:
dotnet restore dotnet build
Spuštěním
dotnet test
příkazu ověřte, že xUnit běží. Pokud jste se rozhodli použít MSTest, měl by se spustit spouštěč konzoly MSTest.
A to je vše! Knihovnu teď můžete otestovat na všech platformách pomocí nástrojů příkazového řádku. Pokud chcete pokračovat v testování, když máte všechno nastavené, testování knihovny je velmi jednoduché:
- Proveďte změny v knihovně.
- Pomocí příkazu spusťte testy z příkazového řádku v testovacím
dotnet test
adresáři.
Kód se při vyvolání příkazu automaticky znovu sestaví dotnet test
.
Jak používat více projektů
Běžnou potřebou větších knihoven je umístit funkce do různých projektů.
Představte si, že chcete vytvořit knihovnu, která by mohla být využita v idiomaticích C# a F#. To by znamenalo, že uživatelé vaší knihovny ji využívají způsoby, které jsou přirozené pro C# nebo F#. Například v jazyce C# můžete knihovnu využívat takto:
using AwesomeLibrary.CSharp;
public Task DoThings(Data data)
{
var convertResult = await AwesomeLibrary.ConvertAsync(data);
var result = AwesomeLibrary.Process(convertResult);
// do something with result
}
V jazyce F# to může vypadat takto:
open AwesomeLibrary.FSharp
let doWork data = async {
let! result = AwesomeLibrary.AsyncConvert data // Uses an F# async function rather than C# async method
// do something with result
}
Scénáře spotřeby, jako je tento, znamenají, že přístupná rozhraní API musí mít jinou strukturu pro C# a F#. Běžným přístupem k tomuto účelu je zohlednit veškerou logiku knihovny do základního projektu pomocí projektů C# a F# definujících vrstvy rozhraní API, které do tohoto základního projektu volají. Zbývající část oddílu bude používat následující názvy:
- AwesomeLibrary.Core – základní projekt, který obsahuje veškerou logiku pro knihovnu
- AwesomeLibrary.CSharp – projekt s veřejnými rozhraními API určenými ke spotřebě v jazyce C#
- AwesomeLibrary.FSharp – projekt s veřejnými rozhraními API určenými ke spotřebě v F#
V terminálu můžete spustit následující příkazy, které vytvoří stejnou strukturu jako v tomto průvodci:
mkdir AwesomeLibrary && cd AwesomeLibrary
dotnet new sln
mkdir AwesomeLibrary.Core && cd AwesomeLibrary.Core && dotnet new classlib
cd ..
mkdir AwesomeLibrary.CSharp && cd AwesomeLibrary.CSharp && dotnet new classlib
cd ..
mkdir AwesomeLibrary.FSharp && cd AwesomeLibrary.FSharp && dotnet new classlib -lang "F#"
cd ..
dotnet sln add AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
dotnet sln add AwesomeLibrary.CSharp/AwesomeLibrary.CSharp.csproj
dotnet sln add AwesomeLibrary.FSharp/AwesomeLibrary.FSharp.fsproj
Tím se přidají výše uvedené tři projekty a soubor řešení, který je propojí dohromady. Vytvoření souboru řešení a propojení projektů vám umožní obnovit a sestavit projekty z nejvyšší úrovně.
Odkazování na projekt
Nejlepším způsobem, jak odkazovat na projekt, je přidat odkaz na projekt pomocí rozhraní příkazového řádku .NET. Z adresářů projektů AwesomeLibrary.CSharp a AwesomeLibrary.FSharp můžete spustit následující příkaz:
dotnet add reference ../AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
Soubory projektu pro AwesomeLibrary.CSharp i AwesomeLibrary.FSharp teď budou odkazovat na ProjectReference
AwesomeLibrary.Core jako cíl. Můžete to ověřit kontrolou souborů projektu a zobrazením následujících možností:
<ItemGroup>
<ProjectReference Include="..\AwesomeLibrary.Core\AwesomeLibrary.Core.csproj" />
</ItemGroup>
Pokud nechcete používat .NET CLI, můžete tento oddíl přidat do každého souboru projektu ručně.
Strukturování řešení
Dalším důležitým aspektem řešení s více projekty je vytvoření dobré celkové struktury projektu. Kód můžete uspořádat tak, jak se vám líbí, a pokud každý projekt propojíte se souborem řešení , dotnet sln add
budete moct spouštět dotnet restore
a dotnet build
na úrovni řešení.