Utveckla bibliotek med .NET CLI
Den här artikeln beskriver hur du skriver bibliotek för .NET med hjälp av .NET CLI. CLI ger en effektiv och låg nivå som fungerar i alla operativsystem som stöds. Du kan fortfarande skapa bibliotek med Visual Studio, och om det är din föredragna upplevelse kan du läsa Visual Studio-guiden.
Förutsättningar
Du behöver .NET SDK installerat på datorn.
För avsnitten i det här dokumentet som hanterar .NET Framework-versioner behöver du .NET Framework installerat på en Windows-dator.
Om du vill stödja äldre .NET Framework-mål måste du dessutom installera målpaket eller utvecklarpaket från nedladdningssidan för .NET Framework. Se den här tabellen:
.NET Framework-version | Vad du ska ladda ned |
---|---|
4.6.1 | Målpaket för .NET Framework 4.6.1 |
4,6 | .NET Framework 4.6-målpaket |
4.5.2 | .NET Framework 4.5.2 Developer Pack |
4.5.1 | .NET Framework 4.5.1 Developer Pack |
4,5 | Windows Software Development Kit för Windows 8 |
4.0 | Windows SDK för Windows 7 och .NET Framework 4 |
2.0, 3.0 och 3.5 | .NET Framework 3.5 SP1 Runtime (eller Windows 8+ version) |
Så här riktar du in dig på .NET 5+ eller .NET Standard
Du styr projektets målramverk genom att lägga till det i projektfilen (.csproj eller .fsproj). Vägledning om hur du väljer mellan att rikta in sig på .NET 5+ eller .NET Standard finns i .NET 5+ och .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>
Om du vill rikta in dig på .NET Framework version 4.0 eller senare, eller om du vill använda ett API som är tillgängligt i .NET Framework men inte i .NET Standard (till exempel System.Drawing
), läser du följande avsnitt och lär dig hur du multitarget.
Så här riktar du in dig på .NET Framework
Kommentar
Dessa instruktioner förutsätter att du har .NET Framework installerat på datorn. Se Förutsättningar för att få beroenden installerade.
Tänk på att vissa av de .NET Framework-versioner som används här inte längre stöds. Läs vanliga frågor och svar om versioner som inte stöds i .NET Framework Support Lifecycle Policy.
Om du vill nå det maximala antalet utvecklare och projekt använder du .NET Framework 4.0 som baslinjemål. Börja med att använda rätt Target Framework Moniker (TFM) som motsvarar den .NET Framework-version som du vill stödja för att rikta in dig på .NET Framework.
.NET Framework-version | TFM |
---|---|
.NET Framework 2.0 | net20 |
.NET Framework 3.0 | net30 |
.NET Framework 3.5 | net35 |
.NET Framework 4.0 | net40 |
Microsoft .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 |
Sedan infogar du den här TFM:en i TargetFramework
avsnittet i projektfilen. Så här skriver du till exempel ett bibliotek som riktar sig till .NET Framework 4.0:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
</Project>
Det var det! Även om detta endast kompilerades för .NET Framework 4 kan du använda biblioteket i nyare versioner av .NET Framework.
Så här gör du multitarget
Kommentar
Följande instruktioner förutsätter att du har .NET Framework installerat på datorn. Läs avsnittet Förutsättningar för att lära dig vilka beroenden du behöver installera och var du kan ladda ned dem från.
Du kan behöva rikta in dig på äldre versioner av .NET Framework när projektet stöder både .NET Framework och .NET. Om du i det här scenariot vill använda nyare API:er och språkkonstruktioner för de nyare målen använder #if
du direktiv i koden. Du kan också behöva lägga till olika paket och beroenden för varje plattform som du riktar in dig på för att inkludera de olika API:er som behövs för varje ärende.
Anta till exempel att du har ett bibliotek som utför nätverksåtgärder via HTTP. För .NET Standard och .NET Framework version 4.5 eller senare kan du använda HttpClient
klassen från System.Net.Http
namnområdet. Tidigare versioner av .NET Framework har HttpClient
dock inte klassen, så du kan använda WebClient
klassen från System.Net
namnområdet för dem i stället.
Projektfilen kan se ut så här:
<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>
Du kommer att märka tre större ändringar här:
- Noden
TargetFramework
har ersatts avTargetFrameworks
och tre TFM uttrycks inuti. - Det finns en
<ItemGroup>
nod för målet somnet40
hämtar en .NET Framework-referens. - Det finns en
<ItemGroup>
nod för målet somnet45
hämtar två .NET Framework-referenser.
Preprocessorsymboler
Byggsystemet är medvetet om följande preprocessorsymboler som används i #if
direktiv:
Målramverk | Symboler | Ytterligare symboler (finns i .NET 5+ SDK:er) |
Plattformssymboler (endast tillgängliga när du anger en OS-specifik TFM) |
---|---|---|---|
.NET Framework | NETFRAMEWORK , NET48 , NET472 , NET471 , NET47 , NET462 , NET461 , NET46 , , NET452 , NET451 , NET45 , NET40 , , NET35 NET20 |
NET48_OR_GREATER , NET472_OR_GREATER , NET471_OR_GREATER , NET47_OR_GREATER , NET462_OR_GREATER , NET461_OR_GREATER , NET46_OR_GREATER , NET452_OR_GREATER , , NET451_OR_GREATER , NET45_OR_GREATER , NET40_OR_GREATER , , , NET35_OR_GREATER NET20_OR_GREATER |
|
.NET Standard | NETSTANDARD , NETSTANDARD2_1 , NETSTANDARD2_0 , NETSTANDARD1_6 , NETSTANDARD1_5 , NETSTANDARD1_4 , , NETSTANDARD1_3 , NETSTANDARD1_2 , , NETSTANDARD1_1 NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER , NETSTANDARD2_0_OR_GREATER , NETSTANDARD1_6_OR_GREATER , NETSTANDARD1_5_OR_GREATER , NETSTANDARD1_4_OR_GREATER , NETSTANDARD1_3_OR_GREATER , , NETSTANDARD1_2_OR_GREATER , , NETSTANDARD1_1_OR_GREATER NETSTANDARD1_0_OR_GREATER |
|
.NET 5+ (och .NET Core) | NET , NET8_0 , NET7_0 , NET6_0 , NET5_0 , NETCOREAPP , NETCOREAPP3_1 , NETCOREAPP3_0 , , NETCOREAPP2_2 , NETCOREAPP2_1 , NETCOREAPP2_0 , , , NETCOREAPP1_1 NETCOREAPP1_0 |
NET8_0_OR_GREATER , NET7_0_OR_GREATER , NET6_0_OR_GREATER , NET5_0_OR_GREATER , NETCOREAPP3_1_OR_GREATER , NETCOREAPP3_0_OR_GREATER , , NETCOREAPP2_2_OR_GREATER , NETCOREAPP2_1_OR_GREATER , NETCOREAPP2_0_OR_GREATER , , , NETCOREAPP1_1_OR_GREATER NETCOREAPP1_0_OR_GREATER |
ANDROID , BROWSER , IOS , MACCATALYST , MACOS , , TVOS , , WINDOWS [OS][version] (till exempel IOS15_1 ),[OS][version]_OR_GREATER (till exempel IOS15_1_OR_GREATER ) |
Kommentar
- Versionslösa symboler definieras oavsett vilken version du riktar in dig på.
- Versionsspecifika symboler definieras endast för den version som du riktar in dig på.
- Symbolerna
<framework>_OR_GREATER
definieras för den version som du riktar in dig på och alla tidigare versioner. Om du till exempel riktar in dig på .NET Framework 2.0 definieras följande symboler:NET20
,NET20_OR_GREATER
,NET11_OR_GREATER
ochNET10_OR_GREATER
. - Symbolerna
NETSTANDARD<x>_<y>_OR_GREATER
definieras endast för .NET Standard-mål och inte för mål som implementerar .NET Standard, till exempel .NET Core och .NET Framework. - Dessa skiljer sig från målramverksmonikers (TFM: er) som används av egenskapen MSBuild
TargetFramework
och NuGet.
Här är ett exempel på användning av villkorsstyrd kompilering per mål:
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
}
}
Om du skapar det här projektet med dotnet build
ser du tre kataloger under bin/
mappen:
net40/
net45/
netstandard2.0/
Var och en .dll
av dessa innehåller filerna för varje mål.
Testa bibliotek på .NET
Det är viktigt att kunna testa på olika plattformar. Du kan använda xUnit eller MSTest direkt. Båda passar perfekt för enhetstestning av biblioteket på .NET. Hur du konfigurerar din lösning med testprojekt beror på lösningens struktur. I följande exempel förutsätts att test- och källkatalogerna finns i samma toppnivåkatalog.
Kommentar
Detta använder vissa .NET CLI-kommandon . Mer information finns i dotnet new och dotnet sln .
Konfigurera din lösning. Du kan göra det med följande kommandon:
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
Detta skapar projekt och kopplar samman dem i en lösning. Din katalog för
SolutionWithSrcAndTest
bör se ut så här:/SolutionWithSrcAndTest |__SolutionWithSrcAndTest.sln |__MyProject/ |__MyProject.Test/
Navigera till testprojektets katalog och lägg till en referens till
MyProject.Test
frånMyProject
.cd MyProject.Test dotnet add reference ../MyProject/MyProject.csproj
Återställa paket och byggprojekt:
dotnet restore dotnet build
Kontrollera att xUnit körs genom att
dotnet test
köra kommandot. Om du väljer att använda MSTest ska MSTest-konsollöparen köras i stället.
Det var det! Nu kan du testa biblioteket på alla plattformar med hjälp av kommandoradsverktyg. Om du vill fortsätta testa nu när allt har konfigurerats är det mycket enkelt att testa biblioteket:
- Gör ändringar i biblioteket.
- Kör tester från kommandoraden i testkatalogen med
dotnet test
kommandot .
Koden återskapas automatiskt när du anropar dotnet test
kommandot.
Så här använder du flera projekt
Ett vanligt behov av större bibliotek är att placera funktioner i olika projekt.
Anta att du vill skapa ett bibliotek som kan användas i idiomatiska C# och F#. Det skulle innebära att användarna av biblioteket använder det på ett sätt som är naturligt för C# eller F#. I C# kan du till exempel använda biblioteket så här:
using AwesomeLibrary.CSharp;
public Task DoThings(Data data)
{
var convertResult = await AwesomeLibrary.ConvertAsync(data);
var result = AwesomeLibrary.Process(convertResult);
// do something with result
}
I F# kan det se ut så här:
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
}
Förbrukningsscenarier som detta innebär att DE API:er som används måste ha en annan struktur för C# och F#. En vanlig metod för att åstadkomma detta är att ta med all logik i ett bibliotek i ett kärnprojekt, med C#- och F#-projekt som definierar DE API-lager som anropar till kärnprojektet. Resten av avsnittet använder följande namn:
- AwesomeLibrary.Core – ett kärnprojekt som innehåller all logik för biblioteket
- AwesomeLibrary.CSharp – ett projekt med offentliga API:er avsedda för förbrukning i C#
- AwesomeLibrary.FSharp – ett projekt med offentliga API:er avsedda för förbrukning i F#
Du kan köra följande kommandon i terminalen för att skapa samma struktur som den här guiden:
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
Detta lägger till de tre projekten ovan och en lösningsfil som länkar ihop dem. Genom att skapa lösningsfilen och länka projekt kan du återställa och skapa projekt från en toppnivå.
Projekt-till-projekt-referens
Det bästa sättet att referera till ett projekt är att använda .NET CLI för att lägga till en projektreferens. Från projektkatalogerna AwesomeLibrary.CSharp och AwesomeLibrary.FSharp kan du köra följande kommando:
dotnet add reference ../AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
Projektfilerna för både AwesomeLibrary.CSharp och AwesomeLibrary.FSharp refererar nu till AwesomeLibrary.Core som mål ProjectReference
. Du kan kontrollera detta genom att granska projektfilerna och se följande i dem:
<ItemGroup>
<ProjectReference Include="..\AwesomeLibrary.Core\AwesomeLibrary.Core.csproj" />
</ItemGroup>
Du kan lägga till det här avsnittet i varje projektfil manuellt om du föredrar att inte använda .NET CLI.
Strukturera en lösning
En annan viktig aspekt av lösningar för flera projekt är att upprätta en bra övergripande projektstruktur. Du kan ordna kod hur du vill, och så länge du länkar varje projekt till lösningsfilen med dotnet sln add
kan du köra dotnet restore
och dotnet build
på lösningsnivå.