Tenho um objeto que é meu estado na memória do programa e também algumas outras funções de trabalho para as quais passo o objeto para modificar o estado. Tenho passado por ref para as funções de trabalhador. No entanto, me deparei com a seguinte função.
byte[] received_s = new byte[2048];
IPEndPoint tmpIpEndPoint = new IPEndPoint(IPAddress.Any, UdpPort_msg);
EndPoint remoteEP = (tmpIpEndPoint);
int sz = soUdp_msg.ReceiveFrom(received_s, ref remoteEP);
Isso me confunde porque received_s
e remoteEP
estão retornando coisas da função. Por que remoteEP
precisa de um ref
e received_s
não precisa ?
Eu também sou um programador AC, então estou tendo problemas para tirar dicas da minha cabeça.
Edit: Parece que os objetos em C # são ponteiros para o objeto subjacente. Portanto, quando você passa um objeto para uma função, pode modificar o conteúdo do objeto por meio do ponteiro e a única coisa passada para a função é o ponteiro para o objeto, de forma que o próprio objeto não seja copiado. Use ref ou out se quiser ser capaz de alternar ou criar um novo objeto na função que é como um ponteiro duplo.
if (int.TryParse(text, out int value)) { ... use value here ... }
Pense em um parâmetro não ref como sendo um ponteiro e um parâmetro ref como um ponteiro duplo. Isso me ajudou muito.
Você quase nunca deve passar valores por ref. Suspeito que, se não fosse por questões de interoperabilidade, a equipe do .Net nunca o teria incluído na especificação original. A maneira OO de lidar com a maioria dos problemas que os parâmetros ref resolvem é:
Para vários valores de retorno
Para primitivas que mudam em um método como resultado da chamada do método (o método tem efeitos colaterais nos parâmetros primitivos)
fonte
IPAddress.TryParse(string, out IPAddress)
.if (int.TryParse("123", out var theInt) { /* use theInt */ }
disso, o tivéssemos.var candidate = int.TrialParse("123"); if (candidate.Parsed) { /* do something with candidate.Value */ }
É mais código, mas é muito mais consistente com o design da linguagem C #.Você provavelmente poderia escrever um aplicativo C # inteiro e nunca passar nenhum objeto / estrutura por ref.
Tive um professor que me disse isso:
Concordo com seu conselho e, em meus mais de cinco anos desde a escola, nunca tive necessidade disso fora de chamar o Framework ou a API do Windows.
fonte
SetName(person, "John Doe")
, a propriedade do nome mudará e essa mudança será refletida para o chamador.Visto que received_s é um array, você está passando um ponteiro para aquele array. A função manipula os dados existentes no local, sem alterar o local ou o ponteiro subjacente. A palavra-chave ref significa que você está passando o ponteiro real para o local e atualizando esse ponteiro na função externa, portanto, o valor na função externa mudará.
Por exemplo, a matriz de bytes é um ponteiro para a mesma memória antes e depois, a memória acabou de ser atualizada.
A referência do Endpoint está, na verdade, atualizando o ponteiro para o Endpoint na função externa para uma nova instância gerada dentro da função.
fonte
Pense em uma referência como significando que você está passando um ponteiro por referência. Não usar um ref significa que você está passando um ponteiro por valor.
Melhor ainda, ignore o que acabei de dizer (provavelmente é enganoso, especialmente com tipos de valor) e leia esta página do MSDN .
fonte
meu entendimento é que todos os objetos derivados da classe Object são passados como ponteiros, enquanto os tipos comuns (int, struct) não são passados como ponteiros e requerem ref. Não tenho certeza sobre string (em última análise, é derivado da classe Object?)
fonte
Embora eu concorde com a resposta geral de Jon Skeet e com algumas das outras respostas, há um caso de uso para usar
ref
, que é para aumentar as otimizações de desempenho. Foi observado durante a criação de perfil de desempenho que definir o valor de retorno de um método tem pequenas implicações de desempenho, ao passo que usarref
como um argumento pelo qual o valor de retorno é preenchido nesse parâmetro resulta na remoção desse pequeno gargalo.Isso é realmente útil apenas onde os esforços de otimização são levados a níveis extremos, sacrificando a legibilidade e talvez a testabilidade e a manutenção para economizar milissegundos ou talvez frações de milissegundos.
fonte
Regra do ponto zero primeiro, primitivos são passados por valor (pilha) e não primitivos por referência (pilha) no contexto de TIPOS envolvidos.
Os parâmetros envolvidos são passados por valor por padrão. Bom post que explica as coisas em detalhes. http://yoda.arachsys.com/csharp/parameters.html
Podemos dizer (com aviso) Tipos não primitivos nada mais são do que Ponteiros E quando os passarmos por ref podemos dizer que estamos passando Ponteiro Duplo
fonte