Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 17 de octubre de 2023
.NET

Sabemos que está feo y no sea especialmente recomendable en muchos casos, pero hay veces en las que es totalmente necesario acceder a miembros privados de una clase. Por ejemplo, sería un requisito  imprescindible si fuéramos a implementar un serializador o deserializador personalizado, o necesitásemos clonar objetos, o simplemente realizar pruebas unitarias a una clase que no ha sido diseñada para ello.

Para conseguirlo, siempre hemos utilizado los mecanismos de introspección de .NET, conocidos por todos como reflexión o por su término en inglés reflection. Por ejemplo, imaginemos una clase como la siguiente, virtualmente inexpugnable:

public class BlackBox
{
    private string _message = "This is a private message";
    private void ShowMessage(string msg) => Console.WriteLine(msg);
    public override string ToString() => _message;
}

Aunque a priori no podemos hacer nada con ella desde fuera, usando reflexión podríamos acceder sin problema a sus miembros privados, ya sean propiedades, campos, métodos o cualquier tipo de elemento, como podemos ver en el siguiente ejemplo:

var instance = new BlackBox();

// Obtenemos el valor del campo privado _message:
var field = typeof(BlackBox)
    .GetField("_message", BindingFlags.NonPublic | BindingFlags.Instance);
var value = field!.GetValue(instance);

// Ahora llamamos al método privado ShowMessage():
var method = typeof(BlackBox)
    .GetMethod("ShowMessage", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(instance, [value]);

// Al ejecutar, se nuestra en consola: "This is a private message"

Sin embargo, de todos es sabido que la reflexión es un mecanismo muy lento, a veces farragoso en su implementación y, sobre todo, incompatible con tree-shaking, que es como se suele llamar la técnica que usan los compiladores de eliminar del código final todas las clases, métodos y propiedades que no se utilizan en el código final. Esta técnica va tomando cada vez más relevancia conforme los compiladores son capaces de crear directamente ejecutables nativos puros, porque permiten reducir de forma considerable el peso de los artefactos creados.

Por esta razón, en .NET 8 se ha incluido una nueva fórmula para acceder a miembros privados, mucho más eficiente y amistosa con AOT, porque se lleva a tiempo de compilación algo que antes obligatoriamente se resolvía en tiempo de ejecución.

lunes, 16 de octubre de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

lunes, 9 de octubre de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

lunes, 2 de octubre de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 26 de septiembre de 2023
.NET

Seguro que más de una vez habéis tenido que construir una abstracción sobre DateTime para poder controlar apropiadamente la obtención de la fecha/hora actual y otras operaciones relacionadas con el tiempo.

Suelen ser bastante útiles cuando creamos pruebas unitarias de métodos que dependan del momento actual. Por ejemplo, ¿cómo testearíamos de forma automática que las dos líneas de ejecución del siguiente método DoSomething() funcionan correctamente? Sería imposible salvo que ejecutásemos las pruebas a una hora determinada, algo que se antoja complicado 😉

public class MyClass
{
    public string DoSomething()
    {
        var now = DateTime.Now;
        return now.Second == 0
            ? "A new minute is starting"
            : "Current second " + now.Second;
    }
}  

Sin duda, una forma mejor y más test friendly sería contar con una abstracción sobre el proveedor de tiempos capaz de retornar la fecha y hora actual, por ejemplo:

public interface IDateTimeProvider
{
    DateTime GetCurrentDateTime();
}

De esta forma, podríamos reescribir la clase MyClass de forma que recibiera por inyección de dependencias nuestro proveedor IDateTimeProvider. Así sería realmente sencillo crear un par de pruebas unitarias que, suministrando los valores correctos a través de esta dependencia, podrían recrear los escenarios a cubrir:

public class MyClass
{
    private readonly IDateTimeServices _dateTimeServices;
    public TimeHelpers(IDateTimeServices dateTimeServices)
    {
        _dateTimeServices = dateTimeServices;
    }
    public string DoSomething()
    {
        var now = _dateTimeServices.GetCurrentDateTime();
        return now.Second == 0
            ? "A new minute is starting"
            : "Current second " + now.Second;
    }
}  

Aunque hacerlo de esta manera en nuestras aplicaciones es lo ideal, hay partes que se quedarían fuera de esta posibilidad, como las bibliotecas de terceros que de alguna forma dependan de las funcionalidades proporcionadas por DateTime.

Por esta razón, .NET 8 va a introducir una abstracción que nos permitirá gestionar estos escenarios de forma más homogénea y generalizada en aplicaciones y componentes .NET. 

Os presento la clase abstracta TimeProvider 😁

lunes, 25 de septiembre de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET