Pruebe en producción sin marcas de agua.
Funciona donde lo necesite.
Obtén 30 días de producto totalmente funcional.
Ténlo en funcionamiento en minutos.
Acceso completo a nuestro equipo de asistencia técnica durante la prueba del producto
Span es un tipo introducido en C# 7.2 como parte del Span
Span en C# permite a los desarrolladores trabajar directamente con la memoria sin recurrir a las tradicionales asignaciones de heap. Ofrece una forma de crear porciones de memoria a partir de matrices existentes u otras fuentes de memoria, eliminando la necesidad de copias de memoria adicionales.
Una de las características más destacadas de C# Span son sus abstracciones de copia cero. En lugar de duplicar datos, Span proporciona una forma de referenciar la memoria existente de forma eficiente. Esto es especialmente beneficioso en situaciones en las que copiar grandes cantidades de datos sería poco práctico o demasiado costoso.
Aunque C# ha sido tradicionalmente un lenguaje de alto nivel y seguro, Span introduce cierto grado de manipulación de memoria de bajo nivel similar al trabajo con punteros en lenguajes como C o C++. Los desarrolladores pueden realizar operaciones de tipo puntero sin sacrificar la seguridad y la naturaleza gestionada de C#.
A pesar de sus capacidades de acceso a memoria de bajo nivel, C# Span sigue siendo inmutable. Esto significa que, aunque permite la manipulación de la memoria, refuerza la seguridad impidiendo modificaciones no intencionadas.
using System;
class Program
{
void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a span that points to the entire array
Span<int> span = array;
// Modify the data using the span
span[2] = 10;
// Print the modified array
foreach (var item in array)
{
Console.WriteLine(item);
}
}
}
using System;
class Program
{
void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a span that points to the entire array
Span<int> span = array;
// Modify the data using the span
span[2] = 10;
// Print the modified array
foreach (var item in array)
{
Console.WriteLine(item);
}
}
}
Mientras Span
He aquí algunos puntos clave.
Como su nombre indica, ReadOnlySpan
Como Span
Como Span
Al igual que con Span
ReadOnlySpan
using System;
class Program
{
static void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a read-only span that points to the entire array
ReadOnlySpan<int> readOnlySpan = array;
// Access and print the data through the read-only span
foreach (var item in readOnlySpan)
{
Console.WriteLine(item);
}
// Note: The following line would result in a compilation error since readOnlySpan is read-only.
// readOnlySpan[2] = 10;
}
}
using System;
class Program
{
static void Main()
{
int[] array = { 1, 2, 3, 4, 5 };
// Create a read-only span that points to the entire array
ReadOnlySpan<int> readOnlySpan = array;
// Access and print the data through the read-only span
foreach (var item in readOnlySpan)
{
Console.WriteLine(item);
}
// Note: The following line would result in a compilation error since readOnlySpan is read-only.
// readOnlySpan[2] = 10;
}
}
Hay muchas maneras diferentes de crear ReadOnlySpan y trabajar con él. A continuación figuran algunos ejemplos.
string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
Utilizar Slice en el ReadOnlySpan
ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
Pasar ReadOnlySpan
void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
// Perform operations on the substring
}
// Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length));
void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
// Perform operations on the substring
}
// Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length));
ReadOnlySpan
int index = stringSpan.IndexOf('W');
int index = stringSpan.IndexOf('W');
ReadOnlySpan
using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
using (var accessor = memmf.CreateViewAccessor())
{
ReadOnlySpan<byte> dataSpan;
accessor.Read(0, out dataSpan);
// Process data directly from the memory-mapped file
ProcessData(dataSpan);
}
}
using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
using (var accessor = memmf.CreateViewAccessor())
{
ReadOnlySpan<byte> dataSpan;
accessor.Read(0, out dataSpan);
// Process data directly from the memory-mapped file
ProcessData(dataSpan);
}
}
ReadOnlySpan
// Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan);
// Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan);
Cuando se trabaja con bibliotecas externas o API que operan con intervalos de caracteres.
void ExternalApiMethod(ReadOnlySpan<char> data)
{
// Call the external API with the character span
}
// Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length));
void ExternalApiMethod(ReadOnlySpan<char> data)
{
// Call the external API with the character span
}
// Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length));
ReadOnlySpan
Aunque Span en C# es una potente función con numerosas ventajas, conlleva ciertas limitaciones y consideraciones, especialmente en el contexto de la memoria contigua y no contigua. Exploremos estas limitaciones:
Span
Desde Span
Span
Span
Mientras Span
Mientras Span
ReadOnlySpan
Ciertas estructuras de datos o escenarios que dependen de memoria no contigua pueden no alinearse bien con ReadOnlySpan
En situaciones que implican memoria no contigua, particularmente aquellas que requieren aritmética de punteros compleja, ReadOnlySpan
Al igual que ocurre con la memoria contigua, es importante tener en cuenta que no todas las API o bibliotecas admiten directamente la memoria no contigua representada por ReadOnlySpan
En C#, Span puede utilizarse eficazmente con memoria no gestionada para realizar operaciones relacionadas con la memoria de forma controlada y eficiente. La memoria no gestionada se refiere a la memoria que no está gestionada por el recolector de basura del tiempo de ejecución de .NET, y a menudo implica el uso de asignaciones y desasignaciones de memoria nativa. He aquí cómo se puede utilizar Span con memoria no gestionada en C#.
Para asignar memoria no gestionada, puede utilizar la clase System.Runtime.InteropServices.MemoryMarshal. El método Marshal.AllocHGlobal asigna memoria y devuelve un puntero al bloque asignado. La memoria asignada o dirección de memoria se mantiene en un puntero unmanagedMemory y tendrá acceso de lectura-escritura. Se puede acceder fácilmente a las regiones contiguas de la memoria.
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use the Span as needed...
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use the Span as needed...
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
En el código fuente anterior, asignamos un bloque de memoria no gestionada utilizando Marshal.AllocHGlobal y luego creamos un Span
Span proporciona métodos como Slice, CopyTo y ToArray que pueden utilizarse para copiar datos entre memoria gestionada y no gestionada de forma eficiente.
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
// Managed array to copy data from
int[] sourceArray = { 1, 2, 3, 4, 5 };
// Allocate unmanaged memory for the destination data
IntPtr destinationPointer = MemoryMarshal.Allocate<int>(sourceArray.Length);
try
{
// Create a Span<int> from the source array
Span<int> sourceSpan = sourceArray;
// Create a Span<int> from the allocated unmanaged memory
Span<int> destinationSpan = MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length);
// Copy data from the source Span<int> to the destination Span<int>
sourceSpan.CopyTo(destinationSpan);
// Print the values in the destination memory
Console.WriteLine("Values in the destination memory:");
foreach (var value in destinationSpan)
{
Console.Write($"{value} ");
}
}
finally
{
// Deallocate the unmanaged memory when done
MemoryMarshal.Free(destinationPointer);
}
}
}
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
// Managed array to copy data from
int[] sourceArray = { 1, 2, 3, 4, 5 };
// Allocate unmanaged memory for the destination data
IntPtr destinationPointer = MemoryMarshal.Allocate<int>(sourceArray.Length);
try
{
// Create a Span<int> from the source array
Span<int> sourceSpan = sourceArray;
// Create a Span<int> from the allocated unmanaged memory
Span<int> destinationSpan = MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length);
// Copy data from the source Span<int> to the destination Span<int>
sourceSpan.CopyTo(destinationSpan);
// Print the values in the destination memory
Console.WriteLine("Values in the destination memory:");
foreach (var value in destinationSpan)
{
Console.Write($"{value} ");
}
}
finally
{
// Deallocate the unmanaged memory when done
MemoryMarshal.Free(destinationPointer);
}
}
}
En este ejemplo:
MemoryMarshal.Allocate
Cuando se trabaja con memoria no gestionada, también se puede utilizar código inseguro con punteros. En tales casos, puede obtener un puntero del Span utilizando el método Unsafe.AsPointer() método.
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use unsafe code to work with pointers
// ref t
unsafe
{
byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
// Use the pointer as needed...
}
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
const int bufferSize = 100;
IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
// Create a Span from the unmanaged memory
Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
// Use unsafe code to work with pointers
// ref t
unsafe
{
byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
// Use the pointer as needed...
}
// Don't forget to free the unmanaged memory when done
Marshal.FreeHGlobal(unmanagedMemory);
}
}
En este ejemplo, utilizamos el método Unsafe.AsPointer para obtener un puntero del Span. Esto nos permite utilizar código inseguro cuando trabajamos directamente con punteros.
Recuerde que, cuando se trabaja con memoria no gestionada, es crucial gestionar la asignación y desasignación correctamente para evitar fugas de memoria. Libere siempre la memoria no gestionada utilizando métodos adecuados, como Marshal.FreeHGlobal(). Además, tenga cuidado al utilizar código no seguro, ya que puede introducir posibles riesgos de seguridad si no se maneja adecuadamente.
El uso de Span junto con llamadas a métodos asíncronos en C# es una potente combinación, especialmente cuando se trata de grandes cantidades de datos u operaciones de E/S. El objetivo es manejar las operaciones asíncronas sin copias innecesarias de datos de forma eficiente. Exploremos cómo puede aprovechar Span en escenarios asíncronos:
Cuando se trata de operaciones de E/S asíncronas, como la lectura o escritura de datos en un flujo, puede utilizar Memory
async Task ProcessDataAsync(Stream stream)
{
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await stream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
async Task ProcessDataAsync(Stream stream)
{
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await stream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
En este ejemplo, el método ReadAsync lee asíncronamente datos de un flujo en el búfer. A continuación, el método ProcessData procesa los datos directamente desde el Span
De forma similar a las operaciones de E/S, cuando se trata de operaciones de archivo asíncronas, puede utilizar Span para procesar datos de forma eficiente sin necesidad de realizar copias adicionales.
async Task ProcessFileAsync(string filePath)
{
const int bufferSize = 4096;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
}
void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
async Task ProcessFileAsync(string filePath)
{
const int bufferSize = 4096;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[bufferSize];
while (true)
{
int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
if (bytesRead == 0)
break;
// Process the data using Span without unnecessary copying
ProcessData(buffer.AsSpan(0, bytesRead));
}
}
}
void ProcessData(Span<byte> data)
{
// Perform operations on the data
}
Aquí, el método ReadAsync lee datos de un flujo de archivos en el búfer, y el método ProcessData procesa los datos directamente desde el Span
Cuando se trabaja con tareas asíncronas que producen o consumen datos, se puede utilizar Memory
async Task<int> ProcessDataAsync(int[] data)
{
// Asynchronous processing of data
await Task.Delay(1000);
// Returning the length of the processed data
return data.Length;
}
async Task Main()
{
int[] inputData = Enumerable.Range(1, 1000).ToArray();
// Process the data asynchronously without copying
int processedLength = await ProcessDataAsync(inputData.AsMemory());
Console.WriteLine($"Processed data length: {processedLength}");
}
async Task<int> ProcessDataAsync(int[] data)
{
// Asynchronous processing of data
await Task.Delay(1000);
// Returning the length of the processed data
return data.Length;
}
async Task Main()
{
int[] inputData = Enumerable.Range(1, 1000).ToArray();
// Process the data asynchronously without copying
int processedLength = await ProcessDataAsync(inputData.AsMemory());
Console.WriteLine($"Processed data length: {processedLength}");
}
En este ejemplo, el método ProcessDataAsync procesa los datos de forma asíncrona y devuelve la longitud de los datos procesados sin necesidad de copias adicionales.
Visión general de la biblioteca IronPDF es la última biblioteca PDF en C# deIron Software que puede utilizarse para generar hermosos documentos PDF sobre la marcha de forma dinámica utilizando código C#. IronPDF ofrece diversas funciones, como la generación de PDF a partir de HTML, la conversión de contenido HTML a PDF, la fusión o división de archivos PDF, etc.
La principal característica de IronPDF es suFuncionalidad de HTML a PDFla traducción debe ser profesional, conservando la precisión técnica y explicando las características y ventajas de estas herramientas para desarrolladores. Puede generar archivos PDF a partir de contenido web, por lo que es ideal para informes, facturas y documentación. Esta herramienta permite convertir archivos HTML, URL y cadenas HTML en archivos PDF.
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convert HTML String to PDF
var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");
// 2. Convert HTML File to PDF
var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convert URL to PDF
var url = "http://ironpdf.com"; // Specify the URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convert HTML String to PDF
var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");
// 2. Convert HTML File to PDF
var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convert URL to PDF
var url = "http://ironpdf.com"; // Specify the URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
IronPDF puede instalarse mediante la aplicaciónGestor de paquetes NuGet para IronPDF o mediante el gestor de paquetes de Visual Studio.
dotnet add package IronPdf
// Or
Install-Package IronPdf
dotnet add package IronPdf
// Or
Install-Package IronPdf
using System;
class Program
{
static void Main()
{
Console.WriteLine("Generating PDF using IronPDF.");
var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
var displayLastName = "<p>First Name is Doe</p>".AsSpan();
var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
var start = @"<!DOCTYPE html>
<html>
<body>".AsSpan();
var end = @"<!DOCTYPE html>
<html>
<body>";
var content = string.Concat(start, displayFirstName, displayLastName, string.Concat(displayAddress, end));
var pdfDocument = new ChromePdfRenderer();
pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
}
}
using System;
class Program
{
static void Main()
{
Console.WriteLine("Generating PDF using IronPDF.");
var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
var displayLastName = "<p>First Name is Doe</p>".AsSpan();
var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
var start = @"<!DOCTYPE html>
<html>
<body>".AsSpan();
var end = @"<!DOCTYPE html>
<html>
<body>";
var content = string.Concat(start, displayFirstName, displayLastName, string.Concat(displayAddress, end));
var pdfDocument = new ChromePdfRenderer();
pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
}
}
En este ejemplo, estamos utilizando Span junto con IronPDF para generar un documento PDF.
Salida:
PDF generado:
Información sobre la licencia de IronPDF. Esta clave debe colocarse en appsettings.json.
"IronPdf.LicenseKey": "your license key"
"IronPdf.LicenseKey": "your license key"
Proporcione su correo electrónico para obtener una licencia de prueba.
Span
VisitePágina de documentación de inicio rápido de IronPDF página.