Behavior of parameters in the class constructor in C#

Asked

Viewed 395 times

5

I have a question regarding the behavior of the parameters passed to the constructor of a class, they are by default ref/out or value? Searching on the behavior of parameters in common methods they are by default values, as this example says:

http://www.dotnetperls.com/parameter

But when I created this example, I realize that what I do outside the scope of the class changes the state of property of the instance, which is private. Is that correct?

public class escopo
{
    public void Controller()
    {
        var lista = CriarLista();
        var teste = new teste(lista);

        lista[0] = "Example";

        teste.testeVeridico();
    }

    public List<String> CriarLista()
    {
        var lista = new List<String>() { "A", "B", "C", "D", "E" };
        return lista;
    }
}

public class teste
{
    private List<String> Lista { get; set; }

    public teste(List<String> lista)
    {
        Lista = lista;
    }

    public bool testeVeridico()
    {
        //retorna true
        return Lista[0] == "Example";
    }
}
  • This answer about passing parameter by value or by reference should be useful to you: http://answall.com/a/59687/14584

2 answers

5


The parameters are by value. At least this is the default. But the data type of it influences your behavior. You have types that are by value and types that are by reference.

Do not confuse parameter passing with type allocation. Passing by value is not the same as having a type by value.

Passing by value means that a copy of the data is made.

Types by value do what you expect since there is a copy of the data you see.

Reference types are also passed by value. But what is the value of reference types? It is a pointer to an object in the heap. It is a memory address. Always. Then the copy is also made, but it is the address that is copied, not the referenced object. It is by value also.

The difference is this guy has an object with a longer lifespan. Internally the value is pointer, but in your code you access this object pointed by it. Any change in it reflects on the object throughout its lifetime, even outside the method where there was the change. This is a characteristic of the type and not of the parameter passage.

Note that if you change the address of the object, then you will see that there was this change in argument passed to the method, whether constructor or not.

I created an example to demonstrate this:

public void OutroTeste(List<string> lista) {
    lista = new List<string>() { "aaa", "bbb" };
    return;
}

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

This method is receiving lista by value. Then it creates a new list with completely different data inside it and have it stored in lista which is the parameter. When I go to the list after running this method, what happens? This new data is gone. The new list only exists inside the method, even though I have assigned it to the parameter, it has not changed, because this time I actually changed the parameter. When you change the elements of the same list as the parameter points, you are changing the pointed object and not the parameter itself.

Learn more about their allocation.

In his example List<T> is a type by reference, is a class. Then everything you change in it, will be reflected in the variable that was used as argument.

A curious fellow is the string. It is a reference, so it is always passed the pointer. But it is immutable and has value semantics, so a change in the object will create a new object that will be allocated at another memory position. Therefore the change will be restricted to the method where this occurred. Unless, of course, the parameter is marked as reference.

Parameters ref

out and ref are used to pass by reference. There you will always pass a reference, to the real value. For reference types, there shall be a reference for the pointer of the type which is nevertheless a reference for the object itself. In this case even in the example above if a new object is created, this will be reflected outside the method.

Therefore types by value or types by reference can make use of the reference passage.

If you’re curious to understand better how does the stack and the heap.

  • Thanks man, very well explained. Thank you!

0

I believe the confusion is in Primitive Types and Objects...

Tipos Primitivos

Primitive type parameters (int, string, bool and etc...) are always passed as values, for example:

    static void Main(string[] args)
    {
        String tipoString = "Valor do Tipo Primitivo";
        Int32 tipoInt = 50;

        //Alterações nos valores?
        MetodoString(tipoString);
        MetodoInt(tipoInt);

        Console.WriteLine(tipoString); // Valor do Tipo Primitivo
        Console.WriteLine(tipoInt); // 50
    }

    static void MetodoString(String aParametro)
    {
        //Neste caso esta mudança apenas e valida neste escopo
        //Pois o parametro do tipo String e passado como Valor
        aParametro = "Mudança de Valor";
    }

    static void MetodoInt(Int32 aParametro)
    {
        //O mesmo ocorre neste caso
        aParametro = 10;
    }

As seen above, both the String value and the Integer did not change when passed by parameter. This is because during passing the parameter a copy of the String value is made "typeString".

Now with objects the story changes a little...

Objects

Object parameters such as (Lists, Controls, Classes Created by Yourself!) are passed through by Reference.

How so Reference?

When passed a list by parameter is not made a copy of all the values of it, however and pass only an address pointing to it, ie only a reference! for example:

    static void Main(string[] args)
    {
        List<String> listaString = new List<String>() { "A", "B", "C" };

        //Alterações nos valores?
        MetodoString(listaString);

        //Comando que impirmi todos os valores da Lista
        listaString.ForEach(f => Console.WriteLine(f)); // A
                                                        // B
                                                        // C
                                                        // D
    }

    static void MetodoString(List<String> aParametroLista)
    {
        //Neste caso É adicionado o valor D na lista pois o Parametro "aParametroLista"
        //Apenas aponta pra minha real lista
        aParametroLista.Add("D");
    }

As seen above in the case of objects when passed by parameter are affected by the scope of the method.

But is it always so? Primitive types will always be passed by value and objects by reference?

The answer is no!

Ref

We can pass primitive type parameters by reference using for example the ref command:

    static void Main(string[] args)
    {
        String tipoString = "Valor do Tipo Primitivo";

        //Alterações nos valores?
        MetodoString(ref tipoString);

        Console.WriteLine(tipoString); // Mudança de Valor
    }

    static void MetodoString(ref String aParametro)
    {
        // Neste caso o valor do parametro Será mudado pois isto é uma Referencia!
        // ou seja apenas um endereço
        aParametro = "Mudança de Valor";
    }

As seen above in this case even primitive values can be passed by reference.

If you’re interested in these References... Search for memory areas like Stack and Heap

Research tip: What are and where are the "stack" and "heap"?

I hope I helped! Good Studies

  • You’re a Java programmer, right? Although the answer isn’t essentially wrong, in C# it’s a little different than what you answered. These are just details, but the terminology used is all that is used in Java, except the ref, obviously. And I make an addendum on the last example. It is not changing the value of string, is creating a new one. The type string has value by reference )i that you called object) but by being immutable has semantics as if it were by value (what you called primitive).

  • @bigown actually the answer is yes essentially wrong because it says that parameters lists, controls, and user classes are passed by reference, but in C# these parameters, by default, are passed by value; and in java they are always passed by value because Java doesn’t even support parameter passing by reference. As usual, there is confusion here between "reference types" and "parameter passage by reference". This answer goes into more detail: http://answall.com/a/59687/14584

  • @Caffé you are right in this, had not attacked me to that paragraph of the answer. Anyway I didn’t like the answer as a whole, but I was trying not to sound aggressive. I think you’ve read my answers that I talk a lot about these differences. I’ll even edit my answer to make it clearer.

Browser other questions tagged

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