Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule opisano sposób pisania bibliotek dla platformy .NET przy użyciu interfejsu wiersza polecenia platformy .NET. Interfejs wiersza polecenia zapewnia wydajne i niskopoziomowe doświadczenie użytkownika, które działa w dowolnym obsługiwanym systemie operacyjnym. Nadal możesz tworzyć biblioteki za pomocą programu Visual Studio, a jeśli jest to preferowane środowisko, zapoznaj się z przewodnikiem programu Visual Studio.
Wymagania wstępne
Potrzebny jest zestaw .NET SDK zainstalowany na maszynie.
W sekcjach tego dokumentu do obsługi wersji programu .NET Framework potrzebny jest program .NET Framework zainstalowany na maszynie z systemem Windows.
Ponadto jeśli chcesz obsługiwać starsze elementy docelowe programu .NET Framework, musisz zainstalować pakiety docelowe lub pakiety deweloperskie ze strony pobierania programu .NET Framework. Zapoznaj się z tą tabelą:
| Wersja systemu .NET Framework | Co pobrać |
|---|---|
| 4.6.1 | Pakiet docelowy programu .NET Framework 4.6.1 |
| 4.6 | Pakiet docelowy programu .NET Framework 4.6 |
| 4.5.2 | Pakiet Dla Programistów .NET Framework 4.5.2 |
| 4.5.1 | .NET Framework 4.5.1 Pakiet dla Programistów |
| 4.5 | Zestaw Windows Software Development Kit dla systemu Windows 8 |
| 4.0 | Zestaw Windows SDK dla systemów Windows 7 i .NET Framework 4 |
| 2.0, 3.0 i 3.5 | Środowisko uruchomieniowe programu .NET Framework 3.5 z dodatkiem SP1 (lub windows 8 lub nowszy) |
Jak kierować na platformę .NET 5+ lub .NET Standard
Możesz kontrolować strukturę docelową projektu, dodając ją do pliku projektu (csproj lub .fsproj). Aby uzyskać wskazówki dotyczące wybierania między platformą .NET 5+ lub .NET Standard, zobacz .NET 5+ i .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>
Jeśli chcesz użyć platformy .NET Framework w wersji 4.0 lub wcześniejszej lub chcesz użyć interfejsu API dostępnego w programie .NET Framework, ale nie w programie .NET Standard (na przykład ), przeczytaj poniższe sekcje i dowiedz się, jak realizować wielocelowe kierowanie.
Jak celować w platformę .NET Framework
Uwaga
W tych instrukcjach założono, że na komputerze jest zainstalowany program .NET Framework. Zapoznaj się z tematem Wymagania wstępne , aby uzyskać zainstalowane zależności.
Pamiętaj, że niektóre wersje programu .NET Framework używane tutaj nie są już obsługiwane. Zapoznaj się z często zadawanymi pytaniami dotyczącymi zasad cyklu życia pomocy technicznej programu .NET Framework dotyczącymi nieobsługiwanych wersji.
Jeśli chcesz osiągnąć maksymalną liczbę deweloperów i projektów, użyj programu .NET Framework 4.0 jako celu odniesienia. Aby celować w .NET Framework, zacznij od użycia poprawnego identyfikatora docelowej platformy (TFM), który odpowiada wersji .NET Framework, której chcesz używać.
| Wersja systemu .NET Framework | moniker platformy docelowej |
|---|---|
| .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 |
Następnie wstawisz ten program TFM do TargetFramework sekcji pliku projektu. Na przykład poniżej przedstawiono sposób pisania biblioteki przeznaczonej dla programu .NET Framework 4.0:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
</Project>
I to wszystko. Mimo że ta kompilacja została skompilowana tylko dla programu .NET Framework 4, można użyć biblioteki w nowszych wersjach programu .NET Framework.
Jak wielotargetować
Uwaga
W poniższych instrukcjach założono, że na maszynie jest zainstalowany program .NET Framework. Zapoznaj się z sekcją Wymagania wstępne , aby dowiedzieć się, które zależności należy zainstalować i skąd je pobrać.
Może być konieczne celowanie w starsze wersje platformy .NET Framework, gdy projekt obsługuje zarówno platformę .NET Framework, jak i platformę .NET. W tym scenariuszu, jeśli chcesz użyć nowszych interfejsów API i konstrukcji językowych dla nowszych platform docelowych, użyj dyrektyw #if w swoim kodzie. Może być również konieczne dodanie różnych pakietów i zależności dla każdej docelowej platformy, aby uwzględnić różne interfejsy API potrzebne w każdym przypadku.
Załóżmy na przykład, że masz bibliotekę, która wykonuje operacje sieciowe za pośrednictwem protokołu HTTP. W przypadku platformy .NET Standard i wersji 4.5 lub nowszej programu .NET Framework można użyć klasy HttpClient z przestrzeni nazw System.Net.Http. Jednak wcześniejsze wersje programu .NET Framework nie mają HttpClient klasy , więc można użyć WebClient klasy z System.Net przestrzeni nazw dla tych elementów.
Plik projektu może wyglądać następująco:
<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>
W tym miejscu zauważysz trzy istotne zmiany:
- Węzeł
TargetFrameworkzostał zastąpiony przezTargetFrameworks, przy czym wewnątrz znajdują się trzy TFM. - Istnieje węzeł
<ItemGroup>dlanet40celu, który przyciąga jedno odwołanie do .NET Framework. - Istnieje węzeł
<ItemGroup>dla docelowegonet45, który ściąga dwa odwołania do .NET Framework.
Symbole preprocesora
System kompilacji zna następujące symbole preprocesora używane w #if dyrektywach:
| Platformy docelowe | Symbole | Dodatkowe symbole (dostępne w zestawach SDK .NET 5+) |
Symbole platformy (dostępne tylko podczas określania programu TFM specyficznego dla systemu operacyjnego) |
|---|---|---|---|
| .NET Framework |
NETFRAMEWORK, NET481, , , NET48NET472NET471NET47NET462NET461NET46NET452NET451NET45NET40NET35NET20 |
NET48_OR_GREATER, NET472_OR_GREATER, NET471_OR_GREATERNET47_OR_GREATERNET462_OR_GREATERNET461_OR_GREATERNET46_OR_GREATERNET452_OR_GREATERNET451_OR_GREATERNET45_OR_GREATERNET40_OR_GREATERNET35_OR_GREATERNET20_OR_GREATER |
|
| .NET Standard |
NETSTANDARD, NETSTANDARD2_1, , , NETSTANDARD2_0NETSTANDARD1_6NETSTANDARD1_5NETSTANDARD1_4NETSTANDARD1_3NETSTANDARD1_2NETSTANDARD1_1NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, , NETSTANDARD1_6_OR_GREATER, NETSTANDARD1_5_OR_GREATERNETSTANDARD1_4_OR_GREATER, NETSTANDARD1_3_OR_GREATER, , NETSTANDARD1_2_OR_GREATERNETSTANDARD1_1_OR_GREATERNETSTANDARD1_0_OR_GREATER |
|
| .NET 5+ (i .NET Core) |
NET, NET10_0, , , NET9_0NET8_0NET7_0NET6_0NET5_0NETCOREAPPNETCOREAPP3_1NETCOREAPP3_0NETCOREAPP2_2NETCOREAPP2_1NETCOREAPP2_0NETCOREAPP1_1NETCOREAPP1_0 |
NET10_0_OR_GREATER, NET9_0_OR_GREATER, NET8_0_OR_GREATERNET7_0_OR_GREATERNET6_0_OR_GREATERNET5_0_OR_GREATERNETCOREAPP3_1_OR_GREATERNETCOREAPP3_0_OR_GREATERNETCOREAPP2_2_OR_GREATERNETCOREAPP2_1_OR_GREATERNETCOREAPP2_0_OR_GREATERNETCOREAPP1_1_OR_GREATERNETCOREAPP1_0_OR_GREATER |
ANDROID, BROWSER, , IOS, MACCATALYSTMACOS, , TVOS, , WINDOWS[OS][version] (na przykład IOS15_1),[OS][version]_OR_GREATER (na przykład IOS15_1_OR_GREATER) |
Uwaga
- Symbole bez wersji są definiowane niezależnie od docelowej wersji.
- Symbole specyficzne dla wersji są definiowane tylko dla docelowej wersji.
- Symbole
<framework>_OR_GREATERsą definiowane dla docelowej wersji i wszystkich wcześniejszych wersji. Jeśli na przykład używasz .NET Framework 2.0, zdefiniowane są następujące symbole:NET20,NET20_OR_GREATER,NET11_OR_GREATERiNET10_OR_GREATER. - Symbole
NETSTANDARD<x>_<y>_OR_GREATERsą definiowane tylko dla obiektów docelowych platformy .NET Standard, a nie dla obiektów docelowych implementujących platformę .NET Standard, takich jak .NET Core i .NET Framework. - Różnią się one od identyfikatorów frameworku docelowego (TFMs) używanych przez właściwość MSBuild i NuGet.
Oto przykład użycia kompilacji warunkowej dla elementu docelowego:
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
}
}
Jeśli stworzysz ten projekt za pomocą dotnet build, zauważysz trzy katalogi w folderze bin/:
net40/
net45/
netstandard2.0/
Każdy z nich zawiera .dll pliki dla każdego obiektu docelowego.
Jak testować biblioteki na platformie .NET
Ważne jest, aby móc testować na różnych platformach. Możesz użyć xUnit lub MSTest z pudełka. Oba są doskonale odpowiednie do testów jednostkowych twojej biblioteki na platformie .NET. Sposób konfigurowania rozwiązania przy użyciu projektów testowych zależy od struktury rozwiązania. W poniższym przykładzie przyjęto założenie, że katalogi testowe i źródłowe działają w tym samym katalogu najwyższego poziomu.
Uwaga
Używa to niektórych poleceń .NET CLI. Aby uzyskać więcej informacji, zobacz dotnet new and dotnet sln .
Skonfiguruj rozwiązanie. Można to zrobić za pomocą następujących poleceń:
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.csprojSpowoduje to utworzenie projektów i połączenie ich razem w rozwiązaniu. Twoja struktura katalogów dla
SolutionWithSrcAndTestpowinna wyglądać następująco:/SolutionWithSrcAndTest |__SolutionWithSrcAndTest.sln |__MyProject/ |__MyProject.Test/Przejdź do katalogu projektu testowego i dodaj odwołanie do
MyProject.TestzMyProject.cd MyProject.Test dotnet reference add ../MyProject/MyProject.csprojPrzywracanie pakietów i kompilowanie projektów.
dotnet restore dotnet buildSprawdź, czy xUnit wykonuje się, uruchamiając polecenie
dotnet test. Jeśli zdecydujesz się użyć narzędzia MSTest, to moduł uruchamiający MSTest w konsoli powinien być uruchomiony zamiast tego.
I to wszystko. Teraz możesz przetestować bibliotekę na wszystkich platformach przy użyciu narzędzi wiersza polecenia. Aby kontynuować testowanie teraz, gdy wszystko jest skonfigurowane, testowanie biblioteki jest bardzo proste:
- Wprowadź zmiany w bibliotece.
- Uruchom testy z wiersza polecenia w katalogu testowym, używając komendy
dotnet test.
Kod zostanie automatycznie skompilowany, gdy wywołasz polecenie dotnet test.
Jak używać wielu projektów
Typowym zapotrzebowaniem na większe biblioteki jest umieszczenie funkcji w różnych projektach.
Wyobraź sobie, że chcesz utworzyć bibliotekę, która może być zużywana w idiomatycznych językach C# i F#. Oznaczałoby to, że użytkownicy biblioteki używają jej w sposób naturalny dla języka C# lub F#. Na przykład w języku C# możesz użyć biblioteki w następujący sposób:
using AwesomeLibrary.CSharp;
public Task DoThings(Data data)
{
var convertResult = await AwesomeLibrary.ConvertAsync(data);
var result = AwesomeLibrary.Process(convertResult);
// do something with result
}
W języku F# może to wyglądać następująco:
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
}
Takie scenariusze użycia oznaczają, że uzyskiwane interfejsy API muszą mieć inną strukturę dla języka C# i języka F#. Typowym podejściem do osiągnięcia tego celu jest uwzględnienie całej logiki biblioteki w podstawowym projekcie przy użyciu projektów języka C# i F# definiujących warstwy interfejsu API wywołujące ten podstawowy projekt. W pozostałej części sekcji będą używane następujące nazwy:
- AwesomeLibrary.Core — podstawowy projekt zawierający całą logikę biblioteki
- AwesomeLibrary.CSharp — projekt z publicznymi interfejsami API przeznaczonymi do użycia w języku C#
- AwesomeLibrary.FSharp — projekt z publicznymi interfejsami API przeznaczonymi do użycia w języku F#
Następujące polecenia można uruchomić w terminalu, aby utworzyć taką samą strukturę jak w tym przewodniku:
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
Spowoduje to dodanie trzech projektów powyżej i pliku rozwiązania, który łączy je ze sobą. Utworzenie pliku rozwiązania i łączenie projektów umożliwi przywracanie i kompilowanie projektów z najwyższego poziomu.
Odwoływanie się z projektu do projektu
Najlepszym sposobem odwołowania się do projektu jest użycie interfejsu wiersza polecenia platformy .NET w celu dodania odwołania do projektu. W katalogach projektów AwesomeLibrary.CSharp i AwesomeLibrary.FSharp można uruchomić następujące polecenie:
dotnet reference add ../AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
Pliki projektu zarówno AwesomeLibrary.CSharp, jak i AwesomeLibrary.FSharp będą teraz odwoływać się do AwesomeLibrary.Core jako ProjectReference elementu docelowego. Możesz to zweryfikować, przeglądając pliki projektu, które zawierają następujące elementy:
<ItemGroup>
<ProjectReference Include="..\AwesomeLibrary.Core\AwesomeLibrary.Core.csproj" />
</ItemGroup>
Tę sekcję można dodać do każdego pliku projektu ręcznie, jeśli nie chcesz używać interfejsu wiersza polecenia platformy .NET.
Tworzenie struktury rozwiązania
Innym ważnym aspektem rozwiązań wieloprojektowych jest ustanowienie dobrej ogólnej struktury projektu. Możesz zorganizować kod w dowolny sposób, a tak długo, jak łączysz każdy projekt z plikiem rozwiązania za pomocą dotnet sln add, będzie można uruchomić dotnet restore i dotnet build na poziomie rozwiązania.