0

Lanzamiento de .Net Community Toolkit 8 #2

Bienvenidos a la continuación del lanzamiento del .NET Community Toolkit. En esta segunda parte, nos sumergimos aún más en las características y herramientas que este conjunto proporciona a la comunidad de desarrolladores. Descubriremos cómo el Toolkit potencia la productividad y la creatividad, ofreciendo soluciones innovadoras y eficientes para los desafíos comunes en el desarrollo de aplicaciones .NET. Desde mejoras en la interfaz de usuario hasta utilidades esenciales, exploraremos en detalle las gemas que hacen del .NET Community Toolkit una valiosa adición a tu conjunto de recursos. Únete a nosotros en este viaje de descubrimiento mientras destacamos las emocionantes funcionalidades que enriquecen el desarrollo .NET en la comunidad.

Compatibilidad con cambios Broadcast para propiedades generadas

Se ha añadido un nuevo atributo [NotifyPropertyChangedRecipients], que se puede utilizar en la propiedad observable generada a partir de un tipo que hereda de ObservableRecipient (o que está anotado con [ObservableRecipient]). Al emplearlo, se generará una llamada al método Broadcast para enviar un mensaje a todos los demás componentes suscritos sobre el cambio de propiedad que acaba de ocurrir. Esto puede ser útil en situaciones donde un cambio en la propiedad de un modelo de vista también debe notificarse a otros componentes de la aplicación (por ejemplo, supongamos que hay una propiedad booleana IsLoggedIn que se actualiza cuando un usuario inicia sesión; esto puede notificar y desencadenar que algunos otros componentes de la aplicación se actualicen con el mensaje difundido).

Se usa:

[ObservableProperty]
[NotifyPropertyChangedRecipients]
private string name;

Produce:

public string Name
{
    get => name;
    set
    {
        if (!EqualityComparer<string>.Default.Equals(name, value))
        {
            OnNameChanging(value);
            OnPropertyChanging();
            string oldValue = name;
            name = value;
            Broadcast(oldValue, value, nameof(Name));
            OnNameChanged();
            OnPropertyChanged();
        }
    }
}

Composición de ViewModel

Debido a la ausencia de herencia múltiple en C#, a veces esto puede suponer un desafío.

¿Qué ocurre si hay un modelo de vista que debe heredar de un tipo específico, pero al mismo tiempo desea incorporar compatibilidad con INotifyPropertyChanged o hacer que también heredé de ObservableRecipient para acceder a sus API?

El kit de herramientas de MVVM ha implementado una solución para este problema mediante la introducción de atributos para la generación de código, lo que facilita la incorporación de lógica de estos tipos en clases arbitrarias. Dichos atributos son [INotifyPropertyChanged], [ObservableObject] y [ObservableRecipient].

Al aplicar estos atributos a una clase, el generador de código fuente de MVVM Toolkit incorporará toda la lógica de ese tipo en esa clase, como si dicha clase también hubiera heredado de ese tipo. Por ejemplo:

[INotifyPropertyChanged]
partial class MyObservableViewModel : DatabaseItem
{
}

Esto heredará de MyObservableViewModel como era de esperar, pero el uso de también le permitirá obtener soporte para [INotifyPropertyChanged], junto con todas las API auxiliares incluidas por ObservableObject.

Se sigue recomendando heredar de los tipos base, como en el caso de ObservableObject, ya que esto también puede contribuir a la reducción del tamaño binario. No obstante, la capacidad de insertar código de esta manera cuando sea necesario puede ser útil para superar las limitaciones de C# en situaciones en las que no es posible cambiar el tipo base de un modelo de vista, como se ejemplifica anteriormente.

Mensajería mejorada en APIs

Otra característica de uso común en MVVM Toolkit es la interfaz IMessenger, que representa un contrato para tipos que se pueden utilizar para intercambiar mensajes entre diferentes objetos. Esto puede resultar beneficioso para desacoplar varios módulos de una aplicación sin la necesidad de mantener referencias directas a los tipos a los que se hace referencia. Además, es posible enviar mensajes a canales específicos, identificados de manera única por un token, y tener distintos mensajeros en diversas secciones de una aplicación.

MVVM Toolkit proporciona dos implementaciones de esta interfaz:

  • WeakReferenceMessenger: que no rootea a los destinatarios y permite recopilarlos. Esto se implementa a través de identificadores dependientes, que son un tipo especial de referencias de GC que permiten a este mensajero asegurarse de que siempre se recopilan los destinatarios registrados, incluso si un controlador registrado hace referencia a ellos, pero no existen otras referencias seguras pendientes a ellos.
  • StrongReferenceMessenger: que es una implementación de mensajería que rootea a los destinatarios registrados para garantizar que permanezcan vivos incluso si el mensajero es el único objeto que hace referencia a ellos.

Ejemplo:

// Declare a message
public sealed record LoggedInUserChangedMessage(User user);

// Register a recipient explicitly...
messenger.Register<MyViewModel, LoggedInUserChangedMessage>(this, static (r, m) =>
{
    // Handle the message here, with r being the recipient and m being the
    // input message. Using the recipient passed as input makes it so that
    // the lambda expression doesn't capture "this", improving performance.
});

// ...or have the viewmodel implement IRecipient<TMessage>...
class MyViewModel : IRecipient<LoggedInUserChangedMessage>
{
    public void Receive(LoggedInUserChangedMessage message)
    {
        // Handle the message here
    }
}

// ...and then register through the interface (other APIs are available too)
messenger.Register<LoggedInuserChangedMessage>(this);

// Send a message from some other module
messenger.Send(new LoggedInUserChangedMessage(user));

Las implementaciones de mensajería en esta nueva versión del kit de herramientas de MVVM han experimentado una significativa optimización en .NET 6 gracias a la incorporación de la nueva API pública DependentHandle, permitiendo que los tipos de mensajería sean aún más eficaces y proporcionen una difusión de mensajes completamente sin asignación. A continuación, se detallan algunos puntos de referencia que ilustran el rendimiento de los mensajeros del kit de herramientas de MVVM en comparación con otros tipos equivalentes de otras bibliotecas de MVVM ampliamente utilizadas:

MétodoSignificarErrorStdDevProporciónRatioSDGen 0Generación 1Asignado
MVVMToolkitStrong4.025 ms0,0177 ms0,0147 ms1.000.00
MVVMToolkitDébil7.549 ms0,0815 ms0,0762 ms1.870.02
MvvmCrossStrong11.483 ms0,0226 ms0,0177 ms2.850.019687.500041.824.022 B
MvvmCrossDébil13.941 ms0,1865 ms0,1744 ms3.470.049687.500041.824.007 B
MVVMLight52.929 ms0,1295 ms0,1011 ms13.140.067600.000033.120.010 B
Estilete91.540 ms0,6362 ms0,4967 ms22.730.1735500.0000153.152.352 B
MvvmGen141,743 ms2,7249 ms2,7983 ms35.310.7019250.000083.328.348 B
Catel148.867 ms2,6825 ms2,5093 ms36.940.645250.000022.736.316 B
Prisma150.077 ms0,5359 ms0,4184 ms37.260.1317500.0000250.000076.096.900 B
CaliburnMicro280,740 ms3,7625 ms3,1418 ms69.740.8288000.00002000.0000381.859.608 B
MauiMessagingCenter673,656 ms1,7619 ms1,3755 ms167.260.638000.000035.588.776 B

Cada prueba comparativa implica enviar 4 mensajes diferentes 1000 veces a 100 destinatarios. Como se evidencia, WeakReferenceMessenger y StrongReferenceMessenger destacan considerablemente en velocidad, siendo los únicos que no generan ninguna asignación de memoria al transmitir mensajes.

API Renovadas

En esta nueva iteración del kit de herramientas de MVVM, se trasladan todos los tipos de colecciones agrupadas observables desde el paquete CommunityToolkit.Common hasta CommunityToolkit.Mvvm. Simultáneamente, se implementan cambios significativos para mejorar la superficie de la API y hacerla más útil en diversos escenarios. Estas API son especialmente valiosas al trabajar con elementos agrupados, como en la presentación de una lista de contactos. Además, ahora incluyen extensiones que simplifican en gran medida operaciones comunes, como insertar un elemento en la posición correcta dentro de un grupo (usando el comparador predeterminado o uno proporcionado) y crear un nuevo grupo si es necesario.

Aplicación de ejemplo MVVM Toolkit

Como complemento a la nueva versión, también hemos lanzado la aplicación de ejemplo en la Tienda Microsoft. Esta aplicación incluye toda la documentación disponible en MS Docs, junto con ejemplos interactivos para muchas de las API disponibles. Su propósito es ser un recurso adicional para el kit de herramientas MVVM, y esperamos que sea de ayuda para aquellos que están comenzando a utilizar esta biblioteca.

Descarga

API de diagnóstico mejoradas

El paquete CommunityToolkit.Diagnostics también ha experimentado mejoras significativas, aprovechando las nuevas características de expresión de argumento de autor de llamada y controlador de cadenas interpoladas de C# 10. Ahora, varias API que antes requerían un ahora también admiten un controlador personalizado. Esto permite que los sitios de llamadas eviten por completo el paso de interpolación si no se produce ninguna excepción, y ya no es necesario indicar manualmente el nombre del argumento.

Comparación:

// Diagnostics 7.1
public static void SampleMethod(int[] array, int index, Span<int> span, string text)
{
    Guard.IsNotNull(array, nameof(array));
    Guard.HasSizeGreaterThanOrEqualTo(array, 10, nameof(array));
    Guard.IsInRangeFor(index, array, nameof(index));
    Guard.HasSizeLessThanOrEqualTo(array, span, nameof(span));
    Guard.IsNotNullOrEmpty(text, nameof(text));
}

// Diagnostics 8.0
public static void SampleMethod(int[] array, int index, Span<int> span, string text)
{
    Guard.IsNotNull(array);
    Guard.HasSizeGreaterThanOrEqualTo(array, 10);
    Guard.IsInRangeFor(index, array);
    Guard.HasSizeLessThanOrEqualTo(array, span);
    Guard.IsNotNullOrEmpty(text);
}

Compatibilidad con .NET 6

La última edición de .NET Community Toolkit también introduce compatibilidad con .NET 6 como un nuevo destino en todas las bibliotecas disponibles. Esto implica diversas mejoras al ejecutarse en el entorno de ejecución de .NET más actual:

  • La compatibilidad con el recorte ahora está habilitada para todas las bibliotecas. Para respaldar esto, todos los paquetes también tienen anotaciones de recorte completas para todas las API, para garantizar que todo sea compatible con el enlazador o que muestre explícitamente las advertencias correctas en tiempo de compilación (por ejemplo, este es el caso de algunas API de validación en MVVM Toolkit, que usan algunas API de la BCL que inherentemente necesitan alguna reflexión para funcionar).
  • La extensión del paquete HighPerformance ahora también es compatible con y .Count<T>()nintnuint
  • Se han introducido otras optimizaciones en todos los paquetes en .NET 6.

Por supuesto, todas las bibliotecas seguirán siendo compatibles con .NET Standard 2.0, lo que significa que también puede seguir haciéndoles referencia desde proyectos con diferentes marcos de destino. Y gracias a la lógica de resolución de paquetes NuGet, si crea una biblioteca con cualquiera de estos paquetes y la orienta a una plataforma más antigua (por ejemplo, .NET Standard 2.0) y un consumidor la referencia desde un proyecto dirigido a una nueva versión de .NET (por ejemplo, .NET 6), seguirá obteniendo automáticamente la versión más optimizada de los ensamblados del kit de herramientas de la comunidad de .NET que esté disponible para ellos.

Conclusión

En esta segunda entrega sobre el .NET Community Toolkit, hemos profundizado en características adicionales que fortalecen el arsenal de herramientas disponibles para los desarrolladores en la plataforma .NET. Desde mejoras en la interfaz de usuario hasta utilidades esenciales, hemos explorado cómo este toolkit aborda de manera efectiva los desafíos comunes en el desarrollo. Esta exploración continúa destacando la versatilidad y la eficacia del toolkit en la comunidad de desarrolladores. Esperamos que estas nuevas revelaciones impulsen la creatividad y productividad de quienes confían en el .NET Community Toolkit como una herramienta valiosa y continua enriquecedora para el desarrollo en .NET.s

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *