Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Esse artigo aborda como escrever bibliotecas para .NET usando a CLI do .NET. A CLI fornece uma experiência eficiente e de baixo nível que funciona em qualquer sistema operacional com suporte. Você ainda pode criar bibliotecas com o Visual Studio e, se essa for sua experiência preferida, consulte o guia do Visual Studio.
Pré-requisitos
Você precisa do SDK do .NET instalado no seu computador.
Para as seções deste documento que tratam de versões do .NET Framework, é necessário ter o .NET Framework instalado em um computador Windows.
Além disso, se você quiser dar suporte a versões mais antigas do .NET Framework, precisará instalar os pacotes de direcionamento ou pacotes de desenvolvedor na página de downloads do .NET Framework. Consulte esta tabela:
| Versão do .NET Framework | O que baixar |
|---|---|
| 4.6.1 | Pacote de Direcionamento do .NET Framework 4.6.1 |
| 4,6 | Pacote de Direcionamento do .NET Framework 4.6 |
| 4.5.2 | Pacote de Desenvolvedor do .NET Framework 4.5.2 |
| 4.5.1 | Pacote de Desenvolvedor do .NET Framework 4.5.1 |
| 4.5 | Software Development Kit do Windows (SDK do Windows) para Windows 8 |
| 4,0 | SDK do Windows para Windows 7 e .NET Framework 4 |
| 2.0, 3.0 e 3.5 | Runtime do .NET Framework 3.5 SP1 (ou versão do Windows 8 ou superior) |
Como definir o alvo para o .NET 5+ ou o .NET Standard
Você controla a estrutura de destino do projeto adicionando-a ao arquivo de projeto (.csproj ou .fsproj). Para obter diretrizes sobre como escolher entre o .NET 5+ ou o .NET Standard, consulte .NET 5+ e .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>
Se quiser direcionar o .NET Framework para as versões 4.0 ou anteriores, ou se quiser usar uma API disponível no .NET Framework mas não no .NET Standard (por exemplo, System.Drawing), leia as seções a seguir para aprender a direcionar múltiplos destinos.
Como direcionar o .NET Framework
Observação
Essas instruções pressupõem que você tenha o .NET Framework instalado no seu computador. Consulte os Pré-requisitos para obter as dependências instaladas.
Lembre que algumas das versões do .NET Framework usadas aqui não têm mais suporte. Consulte as Perguntas Frequentes de Política do Ciclo de Vida de Suporte do .NET Framework sobre versões sem suporte.
Se desejar alcançar o número máximo de projetos e desenvolvedores, use o .NET Framework 4.0 como seu destino de linha de base. Para direcionar para o .NET Framework, comece usando o TFM (Moniker da Estrutura de Destino) correto correspondente à versão do .NET Framework à qual você deseja dar suporte.
| Versão do .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 |
Em seguida, insira esse TFM na seção TargetFramework do arquivo de projeto. Por exemplo, aqui está como você escreveria uma biblioteca direcionada ao .NET Framework 4.0:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
</Project>
Pronto! Embora seja compilada somente para o .NET Framework 4, você pode usar a biblioteca em versões mais recentes do .NET Framework.
Como realizar multitargeting
Observação
As instruções a seguir pressupõem que você tenha o .NET Framework instalado no seu computador. Consulte a seção Pré-requisitos para saber quais dependências você precisa instalar e de onde baixá-las.
Talvez seja necessário direcionar para versões mais antigas do .NET Framework quando seu projeto der suporte ao .NET Framework e ao .NET. Nesse cenário, se você quiser usar APIs mais recentes e construções de linguagem para os destinos mais novos, use as diretivas #if no seu código. Você também pode precisar adicionar diferentes pacotes e dependências para cada plataforma de destino para incluir as diferentes APIs necessárias para cada caso.
Por exemplo, digamos que você tem uma biblioteca que executa operações de rede por meio de HTTP. Para .NET Standard e .NET Framework versões 4.5 ou posterior, você pode usar a classe HttpClient do namespace System.Net.Http. No entanto, versões anteriores do .NET Framework não tem a classe HttpClient, portanto, você pode usar a classe WebClient do namespace System.Net para elas.
O arquivo de projeto seria semelhante a:
<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>
Você notará três alterações importantes aqui:
- O nó
TargetFrameworkfoi substituído peloTargetFrameworkse três TFMs são expressas dentro. - Há um nó
<ItemGroup>para o destinonet40extraindo um que o .NET Framework referencia. - Há um nó
<ItemGroup>para o destinonet45extraindo dois que o .NET Framework referencia.
Símbolos do pré-processador.
O sistema de build reconhece os seguintes símbolos do pré-processador usados nas diretivas #if:
| Frameworks de destino | Símbolos | Símbolos adicionais (disponível em SDKs do .NET 5+) |
Símbolos de plataforma (disponíveis somente quando você especifica um TFM específico do sistema operacional) |
|---|---|---|---|
| .NET Framework |
NETFRAMEWORK, NET481, NET48, NET472, , NET471, NET47, , NET462, NET461, NET46, NET452, , NET451, NET45, NET40, , NET35NET20 |
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_GREATERNET20_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_GREATERNETSTANDARD1_0_OR_GREATER |
|
| .NET 5+ (e .NET Core) |
NET, NET10_0, NET9_0, NET8_0, , NET7_0, NET6_0, , NET5_0, NETCOREAPP, NETCOREAPP3_1, NETCOREAPP3_0, , NETCOREAPP2_2, NETCOREAPP2_1, NETCOREAPP2_0, , NETCOREAPP1_1NETCOREAPP1_0 |
NET10_0_OR_GREATER, NET9_0_OR_GREATER, 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_GREATERNETCOREAPP1_0_OR_GREATER |
ANDROID, BROWSER, IOS, MACCATALYST, , MACOS, TVOS, , WINDOWS[OS][version] (por exemplo, IOS15_1),[OS][version]_OR_GREATER (por exemplo, IOS15_1_OR_GREATER) |
Observação
- Os símbolos sem versão são definidos independentemente da versão que você está visando.
- Os símbolos específicos à versão são definidos apenas para a versão que você está direcionando.
- Os símbolos
<framework>_OR_GREATERsão definidos para a versão que você está almejando e para todas as versões anteriores. Por exemplo, se você estiver direcionando .NET Framework 2.0, os seguintes símbolos serão definidos:NET20,NET20_OR_GREATER,NET11_OR_GREATEReNET10_OR_GREATER. - Os símbolos
NETSTANDARD<x>_<y>_OR_GREATERsão definidos apenas para destinos .NET Standard, e não para destinos que implementam o .NET Standard, como o .NET Core e o .NET Framework. - Eles são diferentes dos TFMs (Moniker da Estrutura de Destino) usados pela propriedade MSBuild
TargetFrameworke pelo NuGet.
Aqui está um exemplo fazendo uso de compilação condicional por destino:
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
}
}
Se você compilar esse projeto com dotnet build, notará três diretórios sob a pasta bin/:
net40/
net45/
netstandard2.0/
Cada um deles contém arquivos .dll para cada destino.
Como testar bibliotecas no .NET
É importante ser capaz de testar em várias plataformas. Você pode usar o xUnit ou MSTest pronto para uso. Ambos são perfeitamente adequados para o teste unitário da sua biblioteca no .NET. A maneira de configurar sua solução com projetos de teste dependerá da estrutura da sua solução. O exemplo a seguir pressupõe que os diretórios de origem e de teste estão no mesmo diretório de nível superior.
Observação
Ele usa alguns comandos da CLI do .NET. Consulte dotnet new e dotnet sln para obter mais informações.
Configure sua solução. Você pode fazer isso usando os seguintes comandos:
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.csprojIsso criará projetos e os conectará em uma solução. O diretório para
SolutionWithSrcAndTestdeve ter esta aparência:/SolutionWithSrcAndTest |__SolutionWithSrcAndTest.sln |__MyProject/ |__MyProject.Test/Navegue até o diretório do projeto de teste e adicione uma referência a
MyProject.TestdeMyProject.cd MyProject.Test dotnet reference add ../MyProject/MyProject.csprojRestaure os pacotes e compile projetos:
dotnet restore dotnet buildVerifique se o xUnit é executado por meio da execução do comando
dotnet test. Se você optar por usar o MSTest, o executor de console do MSTest deverá ser executado.
Pronto! Agora você pode testar sua biblioteca em todas as plataformas usando as ferramentas de linha de comando. É muito simples testar sua biblioteca agora que está tudo configurado:
- Faça alterações na sua biblioteca.
- Execute os testes de linha de comando no diretório de teste com o comando
dotnet test.
Seu código será recriado automaticamente quando você invoca o comando dotnet test.
Como usar vários projetos
Uma necessidade comum das bibliotecas grandes é alocar funcionalidades em diferentes projetos.
Imagine que você deseja construir uma biblioteca que poderia ser consumida de forma idiomática em C# e F#. Isso significa que os consumidores da sua biblioteca o farão de maneiras naturais ao C# ou ao F#. Por exemplo, você poderia consumir a biblioteca em C# dessa forma:
using AwesomeLibrary.CSharp;
public Task DoThings(Data data)
{
var convertResult = await AwesomeLibrary.ConvertAsync(data);
var result = AwesomeLibrary.Process(convertResult);
// do something with result
}
No F#, ela poderia assemelhar-se a:
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
}
Cenários de consumo como esse significam que as APIs que estão sendo acessadas devem ter uma estrutura diferente para C# e F#. Uma abordagem comum para realizar isso é integrar toda a lógica de uma biblioteca em um projeto central, com projetos de C# e F# definindo as camadas de API que chamam esse projeto central. O restante da seção usará os nomes a seguir:
- AwesomeLibrary.Core – Um projeto principal que contém toda a lógica para a biblioteca
- AwesomeLibrary.CSharp – Um projeto com APIs públicas destinadas ao consumo em C#
- AwesomeLibrary.FSharp – Um projeto com APIs públicas destinadas ao consumo em F#
Você pode executar os comandos a seguir no seu terminal para produzir a mesma estrutura que este guia:
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
Isso adicionará os três projetos acima e um arquivo de solução que os vincula. Criar o arquivo de solução e vincular projetos permitirá que você restaure e compile projetos de um nível superior.
Referência de projeto a projeto
A melhor maneira de fazer referência a um projeto é usar a CLI do .NET para adicionar uma referência de projeto. Dos diretórios dos projetos AwesomeLibrary.CSharp e AwesomeLibrary.FSharp, você pode executar o seguinte comando:
dotnet reference add ../AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
Os arquivos de projeto para AwesomeLibrary.CSharp e AwesomeLibrary.FSharp agora farão referência a AwesomeLibrary.Core como um destino ProjectReference. Você pode verificar isso inspecionando os arquivos de projeto e vendo o seguinte neles:
<ItemGroup>
<ProjectReference Include="..\AwesomeLibrary.Core\AwesomeLibrary.Core.csproj" />
</ItemGroup>
Você pode adicionar esta seção a cada arquivo de projeto manualmente se preferir não usar a CLI do .NET.
Estruturar uma solução
Outro aspecto importante das soluções multiprojetos é estabelecer uma boa estrutura de projeto geral. Você pode organizar o código da maneira que desejar, e desde que vincule cada projeto ao arquivo de solução com dotnet sln add, você poderá executar dotnet restore e dotnet build no nível da solução.