Pergunta

Se eu estou passando um objeto para um método, por que eu deveria usar a palavra-chave ref?Esse não é o comportamento padrão, de qualquer maneira?

Por exemplo:

class Program
{
    static void Main(string[] args)
    {
        TestRef t = new TestRef();
        t.Something = "Foo";

        DoSomething(t);
        Console.WriteLine(t.Something);
    }

    static public void DoSomething(TestRef t)
    {
        t.Something = "Bar";
    }
}


public class TestRef
{
    public string Something { get; set; }
}

A saída é "Bar", o que significa que o objeto foi passado como uma referência.

Foi útil?

Solução

Passar um ref se você deseja alterar o que o objeto é:

TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);

void DoSomething(ref TestRef t)
{
  t = new TestRef();
  t.Something = "Not just a changed t, but a completely different TestRef object";
}

Depois de chamar DoSomething, t não se refere ao original new TestRef, mas refere-se a um completamente diferente do objeto.

Isso pode ser muito útil se você deseja alterar o valor de um objeto imutável, e.g.um string.Você não pode alterar o valor de um string uma vez que foi criada.Mas através de um ref, você poderia criar uma função que altera a cadeia de caracteres para outro que tem um valor diferente.

Editar:Como outras pessoas já mencionado.Não é uma boa idéia usar ref a menos que seja necessário.Usando ref dá o método de liberdade para alterar o argumento para outra coisa, os chamadores do método, precisam ser codificados para garantir que eles lidam com essa possibilidade.

Além disso, quando o tipo de parâmetro é um objeto, então o objeto variáveis de agir sempre como referências para o objeto.Isso significa que, quando o ref palavra-chave for usada, você tem uma referência a um valor de referência.Isso permite que você faça coisas como descrito no exemplo dado acima.Mas, quando o tipo de parâmetro é um valor primitivo (por exemplo, int) e, em seguida, se este parâmetro é atribuído dentro do método, o valor do argumento de que foi transmitido será alterado após o retorno de método:

int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10

void Change(ref int x)
{
  x = 5;
}

void WillNotChange(int x)
{
  x = 10;
}

Outras dicas

Você precisa distinguir entre "passar uma referência por valor" e "passar um parâmetro/argumento por referência".

Eu escrevi a Artigo razoavelmente longo sobre o assunto Para evitar ter que escrever cuidadosamente cada vez que isso ocorre em grupos de notícias :)

No .NET Quando você passa qualquer parâmetro para um método, uma cópia é criada. Nos tipos de valor significa que qualquer modificação que você faz com o valor está no escopo do método e é perdida quando você sai do método.

Ao passar um tipo de referência, também é feita uma cópia, mas é uma cópia de uma referência, ou seja, agora você tem duas referências na memória ao mesmo objeto. Portanto, se você usar a referência para modificar o objeto, ele será modificado. Mas se você modificar a própria referência - devemos lembrar que é uma cópia - quaisquer alterações também serão perdidas ao sair do método.

Como as pessoas disseram antes, uma tarefa é uma modificação da referência, assim é perdida:

public void Method1(object obj) {   
 obj = new Object(); 
}

public void Method2(object obj) {  
 obj = _privateObject; 
}

Os métodos acima não modifica o objeto original.

Uma pequena modificação do seu exemplo

 using System;

    class Program
        {
            static void Main(string[] args)
            {
                TestRef t = new TestRef();
                t.Something = "Foo";

                DoSomething(t);
                Console.WriteLine(t.Something);

            }

            static public void DoSomething(TestRef t)
            {
                t = new TestRef();
                t.Something = "Bar";
            }
        }



    public class TestRef
    {
    private string s;
        public string Something 
        { 
            get {return s;} 
            set { s = value; }
        }
    }

Como o Testref é uma classe (que são objetos de referência), você pode alterar o conteúdo dentro de T sem passá -la como uma ref. No entanto, se você passar como um REF, o Testref poderá alterar o que o T original se refere. ou seja, aponte para um objeto diferente.

Com ref você pode escrever:

static public void DoSomething(ref TestRef t)
{
    t = new TestRef();
}

E T será alterado após a conclusão do método.

Pense em variáveis (e.g. foo) de tipos de referência (e.g. List<T>) como a realização de identificadores de objeto a forma "do Objeto #24601".Suponha a instrução foo = new List<int> {1,5,7,9}; causas foo para manter "Objeto #24601" (uma lista com quatro itens).Em seguida, chamar foo.Length vai pedir Objecto #24601 para o seu comprimento, e ele irá responder de 4, então foo.Length será igual a 4.

Se foo é passada para um método sem usar ref, que o método pode fazer alterações para o Objeto #24601.Como conseqüência de tais mudanças, foo.Length talvez não igual a 4.O método em si, no entanto, não será possível alterar foo, que irá continuar para manter "Objeto #24601".

Passando foo como um ref parâmetro irá permitir que o chamado método para fazer mudanças não apenas para o Objeto #24601, mas também para foo em si.O método pode criar um novo Objeto #8675309 e armazenar uma referência para que, em foo.Se ele faz isso, foo não seria mais hold "do Objeto #24601", mas em vez disso, "Objeto #8675309".

Na prática, a referência de tipo de variáveis não conter cadeias do formulário "Objeto #8675309";eles não conter qualquer coisa que pode significativamente convertido em um número.Apesar de cada referência de tipo de variável irá conter algumas padrão de bits, não existe relação fixa entre os padrões de bits armazenados em variáveis e os objetos que eles identificam.Não há nenhuma maneira de código pode extrair informações de um objeto ou uma referência a ele, e, posteriormente, determinar se outra referência identificado o mesmo objeto, a menos que o código seja realizada ou sabia de uma referência que se identificou com o objeto original.

É como passar um ponteiro para um ponteiro em C. em .net, isso permitirá que você mude o que o T original se refere, pessoalmente Embora eu pense que se você estiver fazendo isso no .NET, provavelmente tem um problema de design!

Usando o ref Palavra -chave com tipos de referência Você está efetivamente passando uma referência à referência. De muitas maneiras, é o mesmo que usar o out palavra -chave, mas com a pequena diferença de que não há garantia de que o método realmente atribua qualquer coisa ao refParâmetro ED.

ref imita (ou se comporta) como uma área global apenas para dois escopos:

  • Chamador
  • Callee.

Se você está passando um valor, no entanto, as coisas são diferentes. Você pode forçar um valor a ser aprovado por referência. Isso permite que você passe um número inteiro para um método, por exemplo, e tenha o método modificar o número inteiro em seu nome.

Ref indica se a função pode colocar as mãos no próprio objeto, ou apenas em seu valor.

A passagem por referência não está vinculada a um idioma; É uma estratégia de ligação de parâmetros ao lado de um valor por passe, passe pelo nome, passe por necessidade etc ...

Uma sidenote: o nome da classe TestRef é uma escolha horrível nesse contexto;).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top