Differences in the method call

Asked

Viewed 184 times

10

Why some methods can be called consecutively, example:

string a = "";
a.Replace("a", "b").Replace("b","c");// o replace foi chamado 2x

And others cannot be called the same?

ClasseA A = new ClasseA();
string a = A.Metodo();

Why this happens and what is the difference between the two?

3 answers

8

In this particular case the difference is that the Replace() is a normal method and the ClasseA() is a constructor that returns an object that he just built, but can call it in string, so the question starts with the wrong premise:

public class Program {
    public static void Main() {
        new ClasseA().Metodo();
    }
}

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

Obviously this example the object will not be saved in any variable and in this statement it will be lost and becomes available for collection at any time. If you put a variable to store an object this is what is returned by Metodo() and not the constructor, ie, is the last executed method that will produce some value (in the example I wrote Metodo() returns void then it cannot be kept).

If you want the object to be stored in variable you have to do as it is in the question, but just because it is your object, it is not that it cannot be so, you have the choice. In your example the last method of the first line is the constructor so the variable will receive the constructed object, and the following line applies a method on top of the object referenced by the variable that received the object just before.

variavel = new ClasseA().Metodo();

works, but what will be stored in the variable is the value returned by the method, you can even make it be the object, if it is your wish, an artificial example would be like this:

using static System.Console;

public class Program {
    public static void Main() {
        var variavel = new ClasseA().Metodo();
        WriteLine(variavel);
    }
}

public class ClasseA {
    public ClasseA Metodo() => this;
}

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

This technique is called method chaining and is often used to create what is called interface Fluent. The Replace() question does not use this technique, it returns an object that it needs, has not been returned the this, much less on purpose to be able to string artificially, I believe this was explained at the beginning of the answer. I’m putting this paragraph because the other answers adopt this and it’s not what the question is showing.

To better understand what goes on in the first case is the following:

string a = "";
var tmp = a.Replace("a", "b")
tmp.Replace("b","c");

Only this variable tmp does not exist in the code because it is not necessary. Contrary to what many people find variables only need to exist if a value needs to be stored, not all values need, they can be used directly.

An example that can better show that this chain is circumstantial:

Math.Pow(2, 3).ToString()

Here it uses a number to generate another number which will be the power and that number will be used as string. Chaining of completely different objects.

Any method that returns a value can call another method soon after provided it is a method that that object has available, and all objects have methods since all derive from Object and this has methods. A method that returns void cannot be chained.

The method is applied on top of an object, not important as it is obtained, it can be by a variable, the most common, a property that if confused as if it were a variable, can be a method that returns an object or can be a literal. I realize that people get confused with this. Example of the literals:

10.GetHashCode()
"teste".Replace("s", "x")
new []{1, 2, 3}.IndexOf(2)
(1, 2).ToString()
1..3.ToString()
new StringBuilder("abc").Append("xxx")

The first example is rather inefficient, but the Replace() returns a new object that he has just created (this is important, so it is inefficient), so it can be used to pass to another method that is of the same type. Note that there is an error in this code because despite having created two new objects string with modifications, none of them are stored somewhere and therefore will be lost. And if putting it into a variable is just the result of the second that will be stored, it is probably what they want but created an object without need and without realizing it, because it probably does not know that strings are immutable in C#.

Reinforcing: the question has the wrong premise that the second cases do not need to be done chained if you want, and the first case is a simple circumstantial chaining and not the Pattern design called method chaining.

  • I found the arguments valid, but only in the second part of the question, regarding the differences between the 2. Now, between the first part, the Why, I did not understand. I made a modification that I think will illustrate better.

  • Changing the question after it’s been asked and answered is a tricky thing, but in fact I don’t even know what that change means, or it might even mean I wanted to know something else. Or maybe I don’t change anything important and my answer remains the same, maybe I just invalidated part of the text. If you have any doubts yet, please demonstrate this, but it seems that it would be something that was not in the question.

  • I was even going to edit the answer to talk about editing, but I can’t, it invalidated the question itself because now the second case wants to do something completely different, what was wrong premise turned into something meaningless, if you want to do what is in the question then it was your choice not a language determination, you wrote a code that does not flame consecutive because it was what you wanted.

7


This is because the public method Replace(), which is defined in the class string, returns an object instance that happens to be of the same type as a - in this case, string.

Chain calls result from the fact that you can invoke the same method of instances - possibly different, but not necessarily - of the same class immediately after the return of the method.

If this were not possible you would have to store the returned value, and invoke the method by the new reference:

string a = "";
string b = a.Replace("a", "b");
b.Replace("b","c");

If you identify the individual steps of the sequence of events in your example, you will notice the following:

  • The method string.Replace() is invoked for the a;
  • The returned value is also an instance of string.
  • The method string.Replace() is now invoked for the value returned in the previous step;
  • The value returned is a string.

Another way to view this process:

public class Program {
    public static void Main() {
        new A()
            .Mesmo().Mesmo().Mesmo().Mesmo();

        System.Console.WriteLine();

        new A()
            .Novo().Novo().Novo().Novo();

        System.Console.WriteLine();

        new A() // Cadeia com chamadas mistas
            .Mesmo().Mesmo().Novo().Mesmo().Mesmo().Novo().Mesmo().Mesmo();
    }
}

public class A { // Declaração de classe

    private int counter = 0; //Contador interno da instância

    public A Mesmo() { // O método Mesmo retorna uma instância de A...
        counter++;
        System.Console.Write($"{counter} ");
        return this; // Neste caso, a mesma instância.
    }

    public A Novo() { // O método Novo retorna uma instância de A...
        counter++;
        System.Console.Write($"{counter} ");
        return new A(); // Neste caso, uma nova instância.
    }
}

In the above example you can notice that both the method A.Mesmo() how much A.Novo() return instances of A, thus allowing chained calls - however A.Novo() generates new instances while A.Mesmo() returns to himself (return this;).

The compiled result of the above example is as follows:

1 2 3 4 
1 1 1 1 
1 2 3 1 2 3 1 2

.Net Fiddle

  • Then the ability to do the chaining of the methods is by the constructor(s))?

  • 1

    @Marceloawq almost that - is given by signing of the called method (more specifically, the type returned by the method). At the time of return you can use any available method for the type returned.

4

These methods that apply an action to the object itself and return the modified object itself follow the project pattern called Builder.

Example:

// Podemos ter uma classe Pizza definida da seguinte forma:
public class Pizza {
    private TamanhoPizza tamanho;
    private bool comQueijo;
    private bool comOregano;
    private bool comManjericao;

    public Pizza(TamanhoPizza tamanho) {
        this.tamanho = tamanho;
        this.comQueijo = false;
        this.comOregano = false;
        this.comManjericao = false;
    }

    public Pizza ComQueijo() {
        this.comQueijo = true;
        return this;
    }

    public Pizza ComOregano() {
        this.comOregano = true;
        return this;
    }

    public Pizza ComManjericao() {
        this.comManjericao = true;
        return this;
    }

    public void Comer() {
        Console.WriteLine($"Nhami nhami! Que pizza tamanho ${tamanho} ${comQueijo? "e com queijo" : string.Empty} deliciosa!");
        if (comOregano) {
            Console.WriteLine("E ainda com orégano!");
        }
        if (comManjericao) {
            Console.WriteLine("E ainda com manjericão! Hmmm :)");
        }
    }
}

public enum TamanhoPizza {
    Brotinho,
    Media,
    Grande,
    Big,
    Monster
}

To use the Pizza class, we could do the following:

public class Program {
    public static void Main(string[] args) {
        Pizza pizza = 
            new Pizza(TamanhoPizza.Grande)
                .ComQueijo()
                .ComManjericao();
        ComerPizza(pizza);
    }

    private static void ComerPizza(Pizza pizza) {
        pizza.Comer();
    }
}

Based on the blog of Luís Ricardo.

This is done to enrich the construction of the object and avoids a constructor with many parameters that, without proper documentation, could make the code harder to read.

Browser other questions tagged

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