Opracowywanie bibliotek przy użyciu interfejsu wiersza polecenia platformy .NET
Artykuł
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 niskie środowisko, 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
.NET Framework 4.5.2 Developer Pack
4.5.1
.NET Framework 4.5.1 Developer Pack
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)
Instrukcje dotyczące platformy .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 wyboru między określaniem wartości docelowej platformy .NET 5 lub .NET Standard, zobacz .NET 5+ i .NET Standard.
Jeśli chcesz użyć platformy .NET Framework w wersji 4.0 lub nowszej 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ę, System.Drawingjak wieloskładniowy.
How to target .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 zastosować docelowy program .NET Framework, zacznij od użycia poprawnego programu Target Framework Moniker (TFM), który odpowiada wersji programu .NET Framework, którą chcesz obsługiwać.
Wersja systemu .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
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:
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 skierowanie starszych wersji programu .NET Framework, gdy projekt obsługuje zarówno program .NET Framework, jak i platformę .NET. W tym scenariuszu, jeśli chcesz użyć nowszych interfejsów API i konstrukcji językowych dla nowszych obiektów docelowych, użyj #if dyrektyw w kodzie. Może być również konieczne dodanie różnych pakietów i zależności dla każdej platformy, dla której jest przeznaczona wartość docelowa, aby uwzględnić różne interfejsy API potrzebne dla każdego 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 programu .NET Framework w wersji 4.5 lub nowszej System.Net.Http można użyć HttpClient klasy z przestrzeni nazw. 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ł TargetFramework został zastąpiony przez TargetFrameworksprogram , a trzy maszyny TFM są wyrażane wewnątrz.
<ItemGroup> Istnieje węzeł do net40 ściągania docelowego w jednym odwołaniu programu .NET Framework.
Istnieje węzeł docelowy <ItemGroup>net45 ściągający w dwóch odwołaniach programu .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 .NET 5+ SDK)
Symbole platformy (dostępne tylko podczas określania programu TFM specyficznego dla systemu operacyjnego)
ANDROID, BROWSER, , IOS, MACOSMACCATALYST, , 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_GREATER są definiowane dla docelowej wersji i wszystkich wcześniejszych wersji. Jeśli na przykład używasz platformy .NET Framework 2.0, zdefiniowane są następujące symbole: NET20, , NET20_OR_GREATERNET11_OR_GREATERi NET10_OR_GREATER.
Symbole NETSTANDARD<x>_<y>_OR_GREATER są 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 obiektów docelowych monikers (TFMs) używanych przez właściwość MSBuild TargetFramework 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 skompilujesz ten projekt za pomocą dotnet buildpolecenia , 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. Obie te elementy doskonale nadają się do testowania jednostkowego 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.
Przejdź do katalogu projektu testowego i dodaj odwołanie do MyProject.Test pliku .MyProject
cd MyProject.Test
dotnet add reference ../MyProject/MyProject.csproj
Przywracanie pakietów i projektów kompilacji:
dotnet restore
dotnet build
Sprawdź, czy narzędzie xUnit jest uruchamiane dotnet test , wykonując polecenie . Jeśli zdecydujesz się użyć narzędzia MSTest, moduł uruchamiający konsolę MSTest powinien zamiast tego uruchomić.
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 za dotnet test pomocą polecenia .
Kod zostanie automatycznie skompilowany podczas wywoływania dotnet test polecenia.
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ę 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:
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 sprawdzić, sprawdzając pliki projektu i wyświetlając w nich następujące elementy:
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 jednak zorganizować kod i tak długo, jak łączysz każdy projekt z plikiem rozwiązania za pomocą dotnet sln addpolecenia , będzie można uruchomić dotnet restore i dotnet build na poziomie rozwiązania.
Współpracuj z nami w serwisie GitHub
Źródło tej zawartości można znaleźć w witrynie GitHub, gdzie można również tworzyć i przeglądać problemy i żądania ściągnięcia. Więcej informacji znajdziesz w naszym przewodniku dla współtwórców.
Opinia o produkcie .NET
.NET to projekt typu open source. Wybierz link, aby przekazać opinię:
Utwórz projekt platformy .NET i dowiedz się, jak dodawać pakiety i zarządzać zależnościami pakietów w projekcie. Użyj interfejsu wiersza polecenia platformy .NET Core i rejestru NuGet, aby dodać biblioteki i narzędzia do aplikacji w języku C# przy użyciu programu Visual Studio Code.