Alternative to the use of new when implementing methods that return this in child classes

Asked

Viewed 153 times

2

Taking the example of the following code:

public class Pai
{
    protected string PropriedadeA { get; set; }
    public Pai Metodo1(int valor)
    {
        //Vários procedimentos feitos aqui
        PropriedadeA = "Resultado do tratamento";
        return this;
    }
}

public class Filha : Pai
{
    public new Filha Metodo1(int valor)
    {
        base.Metodo1(valor);
        return this;
    }
}

Is there any alternative to avoid rewriting the method in the class Filha?

This arose from the need to implement the Fluent Interface in several classes. These classes inherit the functionalities of the others and add new.

So that the Fluent Interface work the methods have to return the class Filha and not the class Pai.

public interface IDataConfiguration<TResponse>
{
    TResponse GetData();
    Task<TResponse> GetDataAsync();
}

public interface IDataVideoConfiguration<TResponse> : IDataConfiguration<TResponse>
{
    IDataVideoConfiguration<TResponse> VideoName(string videoName);
    IDataVideoConfiguration<TResponse> CosmoId(string cosmoId);
    IDataVideoConfiguration<TResponse> I_GuideId(string iGuideId);
}

public interface IDataVideoImagesConfiguration<TResponse>
{
    IDataVideoImagesConfiguration<TResponse> VideoName(string videoName);
    IDataVideoImagesConfiguration<TResponse> CosmoId(string cosmoId);
    IDataVideoImagesConfiguration<TResponse> I_GuideId(string iGuideId);

    IDataVideoImagesConfiguration<TResponse> ImageFormatId(string formatId);
    IDataVideoImagesConfiguration<TResponse> ImageSize(string imageSize);
    IDataVideoImagesConfiguration<TResponse> ImageSort(string imageSort);
    TResponse GetData(int count = 0, int offset = 0);
    Task<TResponse> GetDataAsync(int count = 0, int offset = 0);
}  

The class Pai implements IDataVideoConfiguration<TResponse> the problem arises when implementing the class Filha inheriting from Pai:

public class Filha<TResponse> : Pai<TResponse>, IDataVideoImagesConfiguration<TResponse>
  • I don’t know if I understand what you really want. In the form you’re in, you just don’t have to have the method in your daughter. If you really need to have this method to do other things in it, then you should declare the method in Pai as virtual. Other than that, I don’t see any alternatives.

  • Got it. The problem is having to keep declaring the method in the daughter class then? The excessive work? I have the impression that this problem is difficult to solve if there are any. That is, it is probably easier to do that same gambit. I thought about extension methods, but it would be limited to them only being able to access public members.

  • Yes the reason is the work. This situation has arisen quite a while ago. I tried several things and ended up giving up. It was the question about interfaces that reminded me of this issue. Note that at the level of interfaces this is solved using another generic type Tout.

2 answers

3


I will say that I do not know if it solves the problem but at least it helps to have ideas:

using System.Console;

public class Program {
    public static void Main() {
        var pai = new Pai();
        WriteLine(pai.Metodo1(1).GetType());
        var filha = new Filha();
        WriteLine(filha.Metodo1(1).GetType());
        filha.PropriedadeB = "xxx";
        WriteLine(filha.Metodo1(1).GetType());
        var temp = filha.Metodo1(1);
        WriteLine(temp.PropriedadeB);
    }
}

public class Pai : Pai<Pai> { }

public class Pai<T> where T : Pai<T> {
    protected string PropriedadeA { get; set; }
    public T Metodo1(int valor) {
        //Vários procedimentos feitos aqui
        PropriedadeA = "Resultado do tratamento";
        return (T)this;
    }
}

public class Filha : Pai<Filha> {
    public string PropriedadeB { get; set; }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

Surely it has limitations but it already solves something.

But also prepare to have to take the trouble of reproducing methods unnecessarily. Sometimes to simplify the life of the consumer greatly increases the work of the supplier.

  • That was the first thing I tried, but in doing return (T)this;, received the message "Cannot cast Expression of type Parent<T> to T". It never occurred to me to use the clause Where which, of course, would solve the problem.

  • When I was solving this problem I had to do this to compile, then you got lucky and gave p/ apply the same solution. Here the "gambiarra" had to be bigger.

  • The "gambiarra" will avoid having to write many lines of code. The class statement is that it will be a little extensive but, as they are internal, the consumer will not have to instantiate them.

  • Yeah, so I put it in quotes, it’s something that’s useful, but it gets really weird.

  • Only now that I had to instantiate the class did I see the true secret of the solution. I hadn’t realized this: public class Pai : Pai<Pai> { }. Now I realize when you say "looks really weird"

  • He is the only one who can instantiate the class declared in this way. For instantiating the generic class directly, you will have to put the type in the instantiation. But what is the type? Pai? It doesn’t exist, it just exists, the Pai<T>. That is, it would have an infinite recursion. Luckily it has solution.

  • "would have an infinite recursion." That was the conclusion I came to when I wanted to instantiate the class. So I came back here to realize what was missing. Thank you!

  • @ramaral, in case you haven’t noticed, notice that there is an important hierarchical difference between this code and its original. In yours, Daughter inherits from Father. In this one, Father and Daughter are not in the same hierarchical line - instead, both inherit from Father<T>, which is a third class. I mean, what you have here is "father is daughter’s brother", and not a father-daughter relationship.

  • Yes. But in practical terms, and this is what I intended, Daughter inherits from Father<T>, which is where the code is to be reused. Parent only exists to be able to create instances where the generic type is the class itself.

Show 4 more comments

1

I took the following test:

using System;

public class Pai
{
    protected string PropriedadeA { get; set; }
    public Pai Metodo1(int valor)
    {
        //Vários procedimentos feitos aqui
        PropriedadeA = "Resultado do tratamento";
        return this;
    }
}

public class Filha : Pai
{

}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        var filha = new Filha().Metodo1(1);
        Console.WriteLine(filha.GetType());
    }
}

The guy returned was Filha. There is no need to reintroduce the method.

  • I was testing and I got the same result. Unless he wants to do something extra with his daughter’s method and therefore needs to define the method again, then I guess with virtual even.

  • 1

    @bigown The problem is that I cannot access methods/properties declared in the child class without using cast

  • @ramaral put in more complete example that you can see this problem happening. I just tested with virtual and helped understand a little bit the problem. It doesn’t work, because as it is returning this the types of return of the Pai and of Filha are distinct. I’ve never seen a case like this and I’ve never thought about it. Anyway, the new is solving the problem and you want an alternative or it doesn’t work? https://dotnetfiddle.net/Tt3icP

  • @bigown I added to the question the reason for this need.

  • 1

    In this case I think it would be pertinent a question detailing better this need for access, involving a more concrete example.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.