En este artículo se explica cómo escribir bibliotecas para .NET con la CLI de .NET. La CLI proporciona una experiencia eficaz y de bajo nivel que funciona en todos los SO compatibles. De todos modos puede seguir compilando bibliotecas con Visual Studio; si esa es la experiencia de su preferencia, consulte la guía sobre Visual Studio.
En las secciones de este documento que se refieren a las versiones de .NET Framework, necesita tener instalado .NET Framework en una máquina con Windows.
Además, si desea admitir destinos de .NET Framework anteriores, deberá instalar paquetes de destino o desarrollador desde la página de descargas de .NET Framework. Consulte la tabla siguiente:
Versión de .NET Framework
Qué debe descargar
4.6.1
Paquete de compatibilidad de .NET Framework 4.6.1
4.6
Paquete de compatibilidad de .NET Framework 4.6
4.5.2
Paquete de desarrollador de .NET Framework 4.5.2
4.5.1
Paquete de desarrollador de .NET Framework 4.5.1
4.5
Kit de desarrollo de software de Windows para Windows 8
4.0
Windows SDK para Windows 7 y .NET Framework 4
2.0, 3.0 y 3.5
Entorno de ejecución de .NET Framework 3.5 SP1 (o una versión posterior a Windows 8)
Establecimiento de .NET 5+ o .NET Standard como destino
Para controlar la plataforma de destino del proyecto, agréguela al archivo de proyecto ( .csproj o .fsproj). Para obtener instrucciones sobre cómo elegir entre los destinos .NET 5+ o .NET Standard consulte .NET 5+ y .NET Standard.
Si desea tener como destino .NET Framework versión 4.0 o inferior, o bien desea usar una API disponible en .NET Framework pero no disponible en el estándar .NET (por ejemplo, System.Drawing), lea las secciones siguientes y sepa cómo tener compatibilidad con múltiples versiones.
Uso de .NET Framework como destino
Nota
En estas instrucciones se supone que tiene instalado .NET Framework en su máquina. Consulte los requisitos previos para instalar las dependencias.
Si quiere llegar a la mayor cantidad posible de desarrolladores y proyectos, use .NET Framework 4.0 como el destino de línea base. Para tener .NET Framework como destino, comience utilizando el moniker de la plataforma de destino (TFM) correcto que corresponda a la versión de .NET Framework que desea admitir.
Versión de .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
Después, inserte el TFM en la sección TargetFramework de su archivo del proyecto. El siguiente es un ejemplo de cómo podría escribir una biblioteca que tenga como destino .NET Framework 4.0:
Y listo. Aunque esto solo hace la compilación para .NET Framework 4, puede usar la biblioteca en las versiones más recientes de .NET Framework.
Cómo lograr la compatibilidad con varias versiones
Nota
Las instrucciones siguientes suponen que tiene instalado .NET Framework en su máquina. Consulte la sección de requisitos previos para información sobre las dependencias que debe instalar y dónde descargarlas.
Es posible que deba tener como destino versiones anteriores de .NET Framework cuando el proyecto admite .NET Framework y .NET. En este escenario, si desea usar API más recientes y construcciones de lenguaje para los destinos más recientes, use las directivas #if en el código. También es posible que tenga que agregar distintos paquetes y dependencias para cada plataforma que tiene como destino para incluir las distintas API necesarias para cada caso.
Por ejemplo, digamos que tiene una biblioteca que realiza operaciones de red a través de HTTP. En el estándar .NET y .NET Framework versión 4.5 o superiores, puede usar la clase HttpClient del espacio de nombres System.Net.Http. Sin embargo, las versiones anteriores de .NET Framework no tienen la clase HttpClient, por lo que, en su lugar, podría usar la clase WebClient del espacio de nombres System.Net para esas versiones.
Su archivo del proyecto podría tener la siguiente apariencia:
XML
<ProjectSdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFrameworks>netstandard2.0;net40;net45</TargetFrameworks></PropertyGroup><!-- Need to conditionally bring in references for the .NET Framework 4.0 target --><ItemGroupCondition="'$(TargetFramework)' == 'net40'"><ReferenceInclude="System.Net" /></ItemGroup><!-- Need to conditionally bring in references for the .NET Framework 4.5 target --><ItemGroupCondition="'$(TargetFramework)' == 'net45'"><ReferenceInclude="System.Net.Http" /><ReferenceInclude="System.Threading.Tasks" /></ItemGroup></Project>
Observará tres cambios principales aquí:
El nodo TargetFramework se ha reemplazado por TargetFrameworks, y se expresan tres TFM dentro.
Existe un nodo <ItemGroup> para el destino net40 que se dirige a una referencia de .NET Framework.
Existe un nodo <ItemGroup> para el destino net45 que se dirige a dos referencias de .NET Framework.
Símbolos de preprocesador
El sistema de compilación conoce los siguientes símbolos del preprocesador que se usan en las directivas #if:
Versiones de .NET Framework de destino
Símbolos
Símbolos adicionales (disponible en SDK de .NET 5+)
Símbolos de plataforma (solo disponibles cuando se especifica un TFM específico del sistema operativo)
Los símbolos sin versión se definen independientemente de la versión de destino.
Los símbolos específicos de la versión solo se definen para la versión de destino.
Los símbolos <framework>_OR_GREATER se definen para la versión de destino y todas las versiones anteriores. Por ejemplo, si tiene como destino .NET Framework 2.0, se definen los símbolos siguientes: NET20, NET20_OR_GREATER, NET11_OR_GREATER y NET10_OR_GREATER.
Los símbolos NETSTANDARD<x>_<y>_OR_GREATER solo se definen para destinos de .NET Standard y no para destinos que implementan .NET Standard, como .NET Core y .NET Framework.
Aquí se muestra un ejemplo en el que se usa la compilación condicional por destino:
C#
using System;
using System.Text.RegularExpressions;
#if NET40// This only compiles for the .NET Framework 4 targetsusing System.Net;
#else// This compiles for all other targetsusing System.Net.Http;
using System.Threading.Tasks;
#endifnamespaceMultitargetLib
{
publicclassLibrary
{
#if NET40privatereadonly WebClient _client = new WebClient();
privatereadonlyobject _locker = newobject();
#elseprivatereadonly HttpClient _client = new HttpClient();
#endif#if NET40// .NET Framework 4.0 does not have async/awaitpublicstringGetDotNetCount()
{
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!publicasync Task<string> GetDotNetCountAsync()
{
string url = "https://www.dotnetfoundation.org/";
// HttpClient is thread-safe, so no need to explicitly lock herevar result = await _client.GetStringAsync(url);
int dotNetCount = Regex.Matches(result, ".NET").Count;
return$"dotnetfoundation.org mentions .NET {dotNetCount} times in its HTML!";
}
#endif
}
}
Si crea este proyecto con dotnet build, observará tres directorios en la carpeta bin/:
net40/
net45/
netstandard2.0/
Cada uno de ellos contiene los archivos .dll para cada destino.
Prueba de las bibliotecas en .NET
Es importante poder probar las plataformas. Puede usar xUnit o MSTest de fábrica. Ambos son perfectamente adecuados para las pruebas unitarias de su biblioteca en .NET. Cómo configurar la solución con proyectos de prueba dependerá de la estructura de la solución. En el ejemplo siguiente se presupone que los directorios de origen y de prueba residen en el mismo directorio de nivel superior.
Vaya al directorio del proyecto de prueba y agregue una referencia a MyProject.Test desde MyProject.
CLI de .NET
cd MyProject.Test
dotnetadd reference ../MyProject/MyProject.csproj
Restaurar paquetes y crear proyectos:
CLI de .NET
dotnetrestoredotnetbuild
Compruebe que xUnit se ejecuta mediante la ejecución del comando dotnet test. Si decide usar MSTest, entonces debe ejecutarse en su lugar el ejecutor de la consola de MSTest.
Y listo. Ahora puede probar la biblioteca en todas las plataformas; para ello, use herramientas de línea de comandos. Para seguir con las pruebas ahora que ya está todo configurado, probar la biblioteca es un proceso muy simple:
Haga los cambios en la biblioteca.
Ejecute las pruebas desde la línea de comandos, en el directorio de prueba, con el comando dotnet test.
El código se recompilará automáticamente cuando invoque el comando dotnet test.
Uso de varios proyectos
Una necesidad en común de las bibliotecas de mayor tamaño es ubicar la funcionalidad en distintos proyectos.
Imagine que desea compilar una biblioteca que se pudiera consumir en C# y F# idiomático. Eso significaría que los usuarios de las bibliotecas las consumirían de manera natural para C# o F#. Por ejemplo, en C#, podría consumir la biblioteca de la siguiente manera:
C#
using AwesomeLibrary.CSharp;
public Task DoThings(Data data)
{
var convertResult = await AwesomeLibrary.ConvertAsync(data);
var result = AwesomeLibrary.Process(convertResult);
// do something with result
}
En F#, sería de la siguiente manera:
F#
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
}
Escenarios de consumo similares a este significan que las API a las que se tiene acceso deben tener una estructura distinta para C# y para F#. Un enfoque común para lograrlo es factorizar toda la lógica de una biblioteca en un proyecto central, con los proyectos de C# y F# definiendo los niveles de API que hacen llamadas a ese proyecto central. En el resto de la sección se usarán los siguientes nombres:
AwesomeLibrary.Core: un proyecto central que contiene toda la lógica de la biblioteca
AwesomeLibrary.CSharp: un proyecto con API públicas pensado para el consumo en C#
AwesomeLibrary.FSharp: un proyecto con API públicas pensado para el consumo en F#
Puede ejecutar los siguientes comandos en su terminal para generar la misma estructura de esta guía:
CLI de .NET
mkdir AwesomeLibrary && cd AwesomeLibrary
dotnetnewsln
mkdir AwesomeLibrary.Core && cd AwesomeLibrary.Core && dotnetnew classlib
cd ..
mkdir AwesomeLibrary.CSharp && cd AwesomeLibrary.CSharp && dotnetnew classlib
cd ..
mkdir AwesomeLibrary.FSharp && cd AwesomeLibrary.FSharp && dotnetnew classlib -lang"F#"cd ..
dotnetslnadd AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
dotnetslnadd AwesomeLibrary.CSharp/AwesomeLibrary.CSharp.csproj
dotnetslnadd AwesomeLibrary.FSharp/AwesomeLibrary.FSharp.fsproj
Esto agregará los tres proyectos anteriores y un archivo de solución que los vincula conjuntamente. Crear el archivo de solución y vincular los proyectos le permitirá restaurar y crear proyectos desde un nivel superior.
Referencias entre proyectos
La mejor manera de hacer referencia a un proyecto es usar la CLI de .NET para agregar una referencia de proyecto. Desde los directorios del proyecto AwesomeLibrary.CSharp y AwesomeLibrary.FSharp, puede ejecutar el siguiente comando:
Los archivos del proyecto para AwesomeLibrary.CSharp y AwesomeLibrary.FSharp ahora harán referencia a AwesomeLibrary.Core como un destino ProjectReference. Puede comprobar esto inspeccionando los archivos del proyecto y observando lo siguiente en ellos:
Puede agregar esta sección a cada archivo del proyecto manualmente si prefiere no usar la CLI de .NET.
Estructura de una solución
Otro aspecto importante de las soluciones de varios proyectos es establecer una buena estructura de proyecto general. Puede organizar el código de la manera que quiera, y siempre y cuando vincule cada proyecto a su archivo de solución con dotnet sln add, podrá ejecutar dotnet restore y dotnet build en el nivel de solución.
Colaborar con nosotros en GitHub
El origen de este contenido se puede encontrar en GitHub, donde también puede crear y revisar problemas y solicitudes de incorporación de cambios. Para más información, consulte nuestra guía para colaboradores.
Comentarios de .NET
.NET es un proyecto de código abierto. Seleccione un vínculo para proporcionar comentarios:
Cree un proyecto de .NET y aprenda a agregar paquetes y a administrar las dependencias de paquete del proyecto. Use la CLI de .NET Core y el registro de NuGet para agregar bibliotecas y herramientas a sus aplicaciones C# mediante Visual Studio Code.