c# – Possible inheritance between properties of the same name but different types?

Question:

I am implementing a client of a service that provides me with certain classes through a WSDL. These classes themselves put together a somewhat complex structure, but connecting to 2 service methods, the responses are almost identical in terms of objects, with the difference that for some reason the classes have different names. Giving 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 you would like to do is a class, which for example, connects to either of the 2 services, and calculates the sum of the volumes of the balls that were received in response. (Important: I can't modify the proxy classes generated by the WSDL since they are constantly updated) I still don't know how to implement the architecture following SOLID/DRY/KISS so as not to complicate the models. What occurred to me is to make, for example, a Ball or Sphere class that implements CalcularVolumen() with the diameter it has, but I don't know how to make this fit with the other classes. I could make a class that contains a CalcularVolumen(int radio) method and that's it, but the problem I have in reality is that the structure is very complex.

The question is: How can I do so that the response of both service methods (with the possibility of adding more methods) can perform the same calculation without repeating code? If possible, a generic solution because many of these cases were presented to me and the code is repeated. Thanks a lot

Update 1: I can't modify the classes I showed, they are autogenerated. Example of duplicate code that 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;
}

Answer:

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

The usual solution to pass that information to the compiler, so that the compiler would allow you to use the two classes interchangeably, would be to make them both implement an interface with such a field, and use that interface in the volume calculation method.

The problem is that you can't modify classes, so you can't make them implement that interface (besides, an interface can't contain fields, only properties). But there is another solution: use the dynamic type, introduced in the .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 diametro field. This technique is called duck typing .

Finally, be careful, there is an error in your volume calculation formula. When you put (3/4) you are performing integer division, the result of which in C# is always an integer rounded down. In this case it would be 0, so your calculated volume will always be 0. To avoid this, just use (3.0/4) instead, since using a double correctly results in a double (0.75).

Scroll to Top