Esta documentación está en fase de desarrollo y puede contener errores.

Utilidades

Primitivas de concurrencia y limitación, conversiones de tipos y familias de extensiones que trae el paquete Dinaup para .NET.

El paquete Dinaup incluye un módulo de utilidades con primitivas de concurrencia y limitación, conversiones de tipos y métodos de extensión. Todo vive en el paquete principal: no hay nada que instalar aparte.

using Dinaup;

Primitivas de concurrencia y limitación

Piezas pequeñas y probadas para los problemas típicos de ritmo, caché y ejecución en background. Úsalas antes de resolverlo a mano.

Debouncer

Retrasa una acción asíncrona y cancela las llamadas anteriores si llega otra dentro de la ventana. Para operaciones caras disparadas por eventos rápidos (teclas, scroll, redibujados).

var debouncer = new Debouncer(async () => await GuardarBorradorAsync(), 500);

// Cada pulsación reinicia el contador; solo se guarda 500 ms tras la última.
debouncer.Debounce();

ExpirableValue / ExpirableValueAsync

Envuelve un valor con expiración (TTL). Al leerlo, si ha caducado, llama a la función de refresco. Hay versión síncrona y asíncrona, genéricas sobre T.

// Refresca desde una fábrica cada 60 s.
var token = new ExpirableValueAsync<string>(
    async () => await PedirTokenAsync(),
    expirationInSeconds: 60);

string actual = await token.GetValueAsync();

// Versión síncrona con valor inicial o con actualizador.
var config = new ExpirableValue<int>(() => LeerConfig(), expirationInSeconds: 30);
int n = config.GetValue();

RateLimiter

Limita intentos por clave. TryAttempt incrementa el contador de esa clave y devuelve false si supera el máximo. Se reinicia sola al vencer el intervalo.

var limiter = new RateLimiter(maxAttempts: 5, clearInterval: TimeSpan.FromMinutes(1));

if (limiter.TryAttempt(userEmail) == false)
    throw new Exception("Demasiados intentos, prueba en un minuto.");

TokenBucket

Cubo de tokens clásico. Se rellena a refillPerSecond tokens por segundo. TryConsume devuelve true si hay tokens y false si no.

var bucket = new TokenBucket(maxTokens: 100, refillPerSecond: 10);

if (bucket.TryConsume())
    await LlamarApiExternaAsync();

SlidingCounter

Limitador por ventana deslizante. TryAdd devuelve true mientras el número de eventos dentro de la ventana no supere el máximo; poda los eventos antiguos sola.

var counter = new SlidingCounter(maxEvents: 1000, window: TimeSpan.FromSeconds(10));

if (counter.TryAdd() == false)
    return; // pico de actividad: descarta o encola

SerialQueue

Cola FIFO segura entre hilos para ejecutar tareas de una en una. Cada Enqueue devuelve un Task que completa cuando el trabajo termina. Evita ejecuciones concurrentes sin bloquear.

var queue = new SerialQueue();

// Se ejecutan en orden, nunca a la vez.
await queue.Enqueue(async () => await EscribirEnArchivoAsync(a));
var total = await queue.Enqueue(() => Calcular());

IBackgroundTaskQueue

Cola de trabajo asíncrono con descripción por tarea. Enqueue añade trabajo; DequeueAsync bloquea hasta que hay una tarea. QueuedHostedService (un BackgroundService) las consume y ejecuta.

IBackgroundTaskQueue queue = new BackgroundTaskQueue();

queue.Enqueue(async ct => await ProcesarPedidoAsync(pedidoId, ct), "procesar-pedido");

int pendientes = queue.Count();
var resumen = queue.ResumenCola(); // descripción -> cuántas pendientes

Conversiones de tipos

Métodos de extensión para convertir entre tipos sin TryParse a mano ni excepciones inesperadas. Convierten desde String, Object, valores anulables y otros.

FamiliaConvierte aEjemplos de uso
STRStringprecio.STR(), id.STR(), fecha.STR() — formatea decimales y fechas de forma coherente, tolera nulos.
INTIntegertexto.INT(0) (con defecto), texto.INT(min, max, siFalla) (con límites).
ToDate y familiaDate / DateOnly / TimeOnlys.ToDate(), s.ToDateOnly(), s.ToDateDesdeMySQL_utc(), variantes _Nullable y de zona horaria.
ToSQL y familiaLiteral SQLnombre.ToSQL(), fecha.ToSQL_Date(), importe.ToSQL_Decimal() — para concatenar en sentencias.
ToSHA1Hash hexToSHA1(bytes), ToSHA1(texto), ToSHA1(stream).
int cantidad = Request["cantidad"].INT(0);          // 0 si no es número
string fecha = DateTime.UtcNow.ToSQL_Date();          // literal para SQL
string hash  = Dinaup.extensions.ToSHA1(bytes);       // SHA-1 en hex

ToSQL produce literales para concatenar, no parámetros. Escapa comillas y barras al estilo MySQL, así que solo es seguro contra PostgreSQL con standard_conforming_strings=off — el contrato que PGClient ya fija. Fuera de ese contexto, usa consultas parametrizadas.

Familias de extensiones

El módulo añade cientos de métodos de extensión. Estas son las familias que más se usan.

Vacío y nulos

Un test de vacío/nulo unificado para strings, colecciones, fechas, GUIDs y tipos propios.

  • IsEmpty(), IsNotEmpty(), HasContent() — sobre String, List, Dictionary, IEnumerable, Guid, fechas anulables.
  • IsNull(), IsNotNull(), NotEmpty() — sobre Guid y Object.
  • OrEmpty() — devuelve una secuencia vacía si el origen es null (para iterar sin comprobar).
  • IfIsEmpty(valor) — coalescencia a un valor por defecto para números y fechas.
if (report.Rows.IsNotEmpty()) { /* ... */ }
foreach (var x in lista.OrEmpty()) { /* nunca NullReference */ }

Predicados de string

Validación y coincidencia sobre texto.

  • IsEmail(), IsGUID(), IsNumeric(), IsInteger(), IsJson(), IsDateOnly().
  • ContainsWord(), ContainsIgnoreCase(), EqualsIgnoreCase(), StartsWithIgnoreCase(), EndsWithIgnoreCase().
  • MatchAllWords(), MatchPercentage(), ContainsWebSearchMode() — búsqueda por palabras al estilo buscador.

LikeM (comparación múltiple)

Atajo para "¿el valor es igual a alguno de estos?". Elimina los OR anidados. Hay sobrecargas para Integer, Decimal, Guid, Char y String.

if (estado.LikeM(1, 2, 5)) { /* 1, 2 o 5 */ }
if (letra.LikeMIgnoreCase("A", "B", "C")) { /* ... */ }

Guardas de argumentos (ThrowIf_)

Cláusulas de guarda que lanzan una excepción descriptiva si el argumento no cumple.

  • ThrowIf_IsNull(), ThrowIf_IsEmpty() — sobre String, colecciones, Guid, números, fechas.
  • ThrowIf_IsNotGuid(), ThrowIf_IsNotEmail(), ThrowIf_IsNotUrl(), ThrowIf_IsZero().
email.ThrowIf_IsNotEmail(nameof(email));
sectionId.ThrowIf_IsEmpty(nameof(sectionId));

Colecciones

  • GetM(i) — indexado seguro: devuelve el valor por defecto si el índice se sale, en vez de lanzar.
  • HasElements(), HasContent() — presencia sobre arrays, listas y diccionarios.
  • GetRandom(), MoveItemUp(), MoveItemDown(), AddRange() sobre HashSet.

Transformación y numéricas

  • String: RemoveAccents(), RemoveSpecialCharacters(), UppercaseFirst(), ParseBetween(), Trim_PN() (trim seguro con nulos), FormatJson().
  • Numéricas: Between(min, max), IsMultipleOf(), RoundMoney(decimales), Half(), HasDecimalPlaces().

Estas listas son representativas, no exhaustivas: el módulo trae muchas más. Los nombres citados existen en el código; explora por IntelliSense sobre el tipo que estés usando.

On this page