¿Hay una mejor manera de implementar esta interfaz IEquatable con tipos genéricos

Actualmente tengo una clase que es casi un envoltorio alrededor de un Booleano para representar un valor de algún hardware físico. Tendré otra clase como esta que es doble. A medida que el sistema crece podemos tener tipos más complejos así que quiero que las cosas sean expandibles, pero estoy empezando aquí. Todas estas clases representan valores físicos por lo que necesitan ser ecualables para poder comprobar su validez. Los he implementado hasta ahora:

Tengo una interfaz ISignalValue que implementa IEquatable

    public interface ISignalValue : IEquatable
    {
       public string AssociatedSignal { get; set; }
    }

Entonces tengo una clase base genérica que implementa esta interfaz, y de la cual cada Valor de Señal heredará.

public class SignalValue : ISignalValue
{
    public readonly T Value;

    public SignalValue(T value)
    {
        Value = value;
    }

    public string AssociatedSignal { get; set; }

    public bool Equals(ISignalValue other)
    {

        if (Value is IEquatable)
        {
            return Value.Equals((IEquatable)other);
        }
        else return false;
    }   
}

Por último, aquí hay un valor de señal que he implementado.

public class DiscreteValue : SignalValue
{
    public DiscreteValue(bool value) : base(value){}

    public double ToDouble() => Value ? 1 : 0;

    public static implicit operator DiscreteValue(bool b) => new DiscreteValue(b);
    public static implicit operator bool(DiscreteValue d) => d.Value;

}

Creé a los operadores implícitos porque quiero que el usuario de la clase pueda hacer cosas como discreteValue.Equals(true) así que no necesitan hacer cosas como discreteValue.Equals(new DiscreteValue(true))

Todo esto funciona bien. Pero lo que me pregunto es, ¿hay una mejor manera de implementar esto, más específicamente, la interfaz IEquatable? Por alguna razón, definir un Valor Discreto como DiscreteValue : SignalValue Parece extraño. Un DiscreteValue es un Valor de Señal del tipo DiscreteValue? Se siente como usar la palabra en una definición de la palabra misma.

Mi pensamiento inicial era definir un Valor Discreta como DiscreteValue: SignalValue que tiene más sentido. Pero el problema con eso es, cuando hago algo como lo siguiente fallará porque uno es IEquatable y el otro es IEquatable.

Tengo esta excepción:

Incapaz de lanzar objeto de tipo '-omitted-. Valores.DescreteValue' para escribir 'System.IEquatable`1[System.Boolean] '

public bool Equals(ISignalValue other)
{

   if (Value is IEquatable)
   {
     return Value.Equals((IEquatable)other);
   }
   else return false;
 }   

Así que, ¿hay una mejor manera de lidiar con esto, o está definiendo un Discreto Valor DiscreteValue: SignalValue ¿La manera de ir?

Pregunta hecha hace 3 años, 4 meses, 28 días - Por techwizkid


2 Respuestas:

  • Una posible solución a este problema sería modificar la implementación de la interfaz IEquatable en la clase base genérica SignalValue. En lugar de comparar directamente el valor con el tipo genérico T, podrías solicitar una comparación usando un objeto del tipo IEquatable.

    Aquí te muestro cómo podrías modificar tu implementación:

    csharp
    public class SignalValue : ISignalValue
    {
        public readonly T Value;
    
        public SignalValue(T value)
        {
            Value = value;
        }
    
        public string AssociatedSignal { get; set; }
    
        public bool Equals(ISignalValue other)
        {
            if (other is SignalValue otherSignalValue)
            {
                if (Value is IEquatable)
                {
                    return ((IEquatable)Value).Equals(otherSignalValue.Value);
                }
                else
                {
                    return false;
                }
            }
            return false;
        }
    }
    

    En este código, verificamos primero si el objeto other es una instancia de SignalValue para poder acceder a su Value. Luego, verificamos si el Value de la instancia actual es de tipo IEquatable y realizamos la comparación de igualdad utilizando este tipo.

    Con esta modificación, puedes definir una clase DiscreteValue como DiscreteValue : SignalValue<bool>, lo cual tiene más sentido en términos de la semántica. Y al realizar una comparación de igualdad, puedes utilizar los operadores implícitos como lo tenías en mente, como por ejemplo discreteValue.Equals(true).

    Espero que esta solución te ayude a mejorar la implementación de la interfaz IEquatable con tipos genéricos en tu código.

    Respondida el Dec 19, 2020 a las 19:37 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Hay algunas formas de mejorar la implementación de la interfaz IEquatable<ISignalValue> para tipos genéricos:

    Usar restricción de tipo genérico:

    En lugar de verificar si Value implementa IEquatable<T>, puedes utilizar una restricción de tipo genérico en la clase SignalValue<T> para garantizar que T implemente IEquatable<T>:

    
    public class SignalValue : ISignalValue where T : IEquatable
    {
        // Implementación restante...
    }
    

    Utilizar el tipo base en la interfaz:

    Puedes definir la interfaz IEquatable para aceptar el tipo base ISignalValue en lugar de un parámetro genérico:

    
    public interface ISignalValue
    {
        string AssociatedSignal { get; set; }
    }
    
    public interface IEquatable where T : ISignalValue
    {
        bool Equals(T other);
    }
    

    Implementar IEquatable<bool> para DiscreteValue:

    Como DiscreteValue representa un valor booleano, puedes implementar directamente la interfaz IEquatable<bool> para ello:

    
    public class DiscreteValue : ISignalValue, IEquatable
    {
        // Implementación restante...
    
        public bool Equals(bool other)
        {
            return Value == other;
        }
    }
    

    De esta manera, no es necesario realizar una comprobación de tipo en el método Equals de SignalValue<T>, y la implementación de DiscreteValue será más eficiente.

    Ejemplo de uso:

    Con las mejoras implementadas, puedes utilizar DiscreteValue de la siguiente manera:

    
    DiscreteValue dv1 = new DiscreteValue(true);
    DiscreteValue dv2 = new DiscreteValue(false);
    
    Console.WriteLine(dv1.Equals(true)); // True
    Console.WriteLine(dv1.Equals(dv2)); // False
    

    Estas mejoras simplifican la implementación de la interfaz IEquatable para tipos genéricos y hacen que el código sea más eficiente y legible.

    Respondida el Dec 19, 2020 a las 19:45 - por Gemini

    Votos positivos: 0 | Votos negativos: 0