Possible inheritance between properties of the same name but of a different type?

4

I am implementing a client of a service that provides me certain classes through a WSDL. In itself these classes build a structure a bit complex, but connecting to 2 service methods the answers are almost identical in terms of objects, with the difference that for some reason the classes have different names. Setting an example:

partial class PelotasServicio1 : object{
    List<Pelota1> pelotas;
}
partial class Pelota1 : object {
    string color;
    float diametro;
}
partial class PelotasServicio2 : object {
    List<Pelota2> pelotas;
}
partial class Pelota2 : object {
    string color;
    float diametro;
}

What I would like to do is a class, which, for example, connects to any of the 2 services, and calculate the sum of the volumes of the balls that were received in response. (Important: I can not modify the proxy classes generated by the WSDL since they are constantly updated) I still do not know how to implement the architecture following SOLID / DRY / KISS so as not to complicate the models. What I came up with is to make for example a Ball or Sphere class that implements CalcularVolumen() with the diameter it has, but I do not know how to fit this with the other classes. I could make a class that contains a CalcularVolumen(int radio) method and already, but the problem I have in reality is that the structure has a lot of complexity.

The question is: How can I do so that the response of both methods of the service (with the possibility of adding more methods) can perform the same calculation without repeating code? As much as possible a generic solution because I was presented with many of these cases and the code is repeated. Thank you very much

Update 1: I can not modify the classes I showed, they are self-generated. Example of duplicate code I want to avoid:

// Suma los volúmenes de las pelotas del servicio 1
public double ConsumirServicio1() {
    PelotasServicio1 servicio1Response = _ws.GetServicio1();
    double suma = 0;
    foreach (Pelota1 pelota in servicio1Response.pelotas) {
        suma += (3/4)*Math.PI*Math.Pow((pelota.diametro / 2), 3);
    }
    return suma;
}

// Suma los volúmenes de las pelotas del servicio 2
public double ConsumirServicio2() {
    PelotasServicio2 servicio2Response = _ws.GetServicio2();
    double suma = 0;
    foreach (Pelota2 pelota in servicio2Response.pelotas) {
        suma += (3/4)*Math.PI*Math.Pow((pelota.diametro / 2), 3);
    }
    return suma;
}
    
asked by Cristhian Valencia 05.12.2017 в 20:31
source

1 answer

4

The fundamental problem is that you know one thing that the compiler does not know: that both class Pelota1 and class Pelota2 have an identical field float diametro .

The usual solution to transmit this information to the compiler, so that it allows you to use both classes indiscriminately, would be to have both implement an interface with such a field, and use that interface in the volume calculation method.

The problem is that you can not modify the classes, so you can not make them implement that interface (besides that an interface can not contain fields, only properties). But there is another solution: use type dynamic , introduced in .NET Framework 4:

// Suma los volúmenes de las pelotas del servicio 1
public double ConsumirServicio1()
{
    PelotasServicio1 servicio1Response = _ws.GetServicio1();
    return CalcularVolumenPelotas(servicio1Response.pelotas);

}

// Suma los volúmenes de las pelotas del servicio 2
public double ConsumirServicio2()
{
    PelotasServicio2 servicio2Response = _ws.GetServicio2();
    return CalcularVolumenPelotas(servicio2Response.pelotas);
}

private double CalcularVolumenPelotas(IEnumerable<dynamic> pelotas)
{
    double suma = 0;
    foreach (dynamic pelota in pelotas)
    {
        suma += (3.0 / 4) * Math.PI * Math.Pow((pelota.diametro / 2), 3);
    }
    return suma;
}

With this you can use any class that has a field diametro . This technique is called duck typing .

To finish, be careful, there is an error in your formula for calculating the volume. When you put (3/4) you are doing an integer division, whose result in C # is always a whole rounded down. In this case it would be 0, so your calculated volume will always be 0. To avoid this it is enough to use instead (3.0/4) , since when using a double , the result is correctly a double (0.75).

    
answered by 05.12.2017 / 23:50
source