Como descartar explicitamente um argumento de fora?


99

Estou fazendo uma ligação:

myResult = MakeMyCall(inputParams, out messages);

mas eu realmente não me importo com as mensagens. Se fosse um parâmetro de entrada com o qual eu não me importasse, apenas passaria um nulo. Se fosse o retorno que eu não me importasse, simplesmente deixaria de lado.

Existe uma maneira de fazer algo semelhante com uma saída ou preciso declarar uma variável que irei ignorar?


Pergunta semelhante aqui: stackoverflow.com/questions/2870544/…
Dunc


Obrigado! É uma pena que não esteja na versão mais recente.
Andrew Ducker,

Respostas:


99

A partir do C # 7.0, é possível evitar a pré-declaração de parâmetros, bem como ignorá-los.

public void PrintCoordinates(Point p)
{
    p.GetCoordinates(out int x, out int y);
    WriteLine($"({x}, {y})");
}

public void PrintXCoordinate(Point p)
{
    p.GetCoordinates(out int x, out _); // I only care about x
    WriteLine($"{x}");
}

Fonte: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/


1
Infelizmente, isso não está incluído no C # 7 (em abril de 2017).
tia de

2
@tia. Eu atualizei minha resposta. Aparentemente, o caractere curinga foi alterado de *para _. Lamentamos que demorou tanto tempo.
Nolonar de

14
Eles deveriam ter seguido a ideia de usar out voida sintaxe, e o sublinhado parece uma escolha estranha.
David Anderson,

1
@ DavidAnderson-DCOM Embora eu não seja fã de sublinhado, acho que eles precisam do nome do tipo para resolução de sobrecarga.
Jonathan Allen

Parece que ainda cria um parâmetro, porque posso adicionar a linha _ = {a value};após a chamada da função sem erros de compilação.
Bip901

37

Infelizmente, você precisa passar algo porque o método é necessário para defini-lo. Portanto, você não pode enviar nullporque o método, sendo necessário para configurá-lo, explodiria.

Uma abordagem para esconder a feiura seria envolver o método em outro método que faça o outparâmetro para você, assim:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Então você pode chamar Other_MakeMyCallsem ter que mexer com outparâmetros desnecessários.


37

Você deve declarar uma variável que irá então ignorar. Este é mais comumente o caso com o padrão TryParse (ou TryWhatever), quando é usado para testar a validade da entrada do usuário (por exemplo, pode ser analisado como um número?) Sem se preocupar com o valor real analisado.

Você usou a palavra "dispose" na pergunta, o que eu suspeito que foi apenas uma pena - mas se o parâmetro out for de um tipo que implementa IDisposable, você certamente deve chamar Dispose, a menos que a documentação do método declare explicitamente que receber o valor não confere propriedade. Não me lembro de alguma vez ter visto um método com um outparâmetro descartável , então espero que esta tenha sido apenas uma escolha de palavras infeliz.


Mais de um antipadrão pragmático
Jodrell,

11

Se a função original for declarada assim:

class C
{
    public Result MakeMyCall(Object arg, out List<String> messages);
}

Você pode declarar um método de extensão como este:

static class CExtension
{
    public static Result MakeMyCall(this C obj, Object arg)
    {
        List<String> unused;
        return obj.MakeMyCall(arg, out unused);
    }
}

O método de extensão se comportará como uma sobrecarga que torna o parâmetro out opcional.


4

O compilador do Visual Basic faz isso criando uma variável fictícia. C # pode fazer isso, se você puder convencer a Microsoft de que é uma boa ideia.


0

Se for a classe de messagesimplementos IDisposable, você não deve ignorá-la. Considere algo como a seguinte abordagem (pode não ser sintaticamente correto, já que não escrevo C # há algum tempo):

using (FooClass messages) {
    myResult = MakeMyCall(inputParams, messages);
}

Uma vez fora do usingbloco, messagesserão descartados automaticamente.


1
Interessante. Mas você não tem que inicializar a variável na instrução using?
OregonGhost de

1
@OregonGhost: Sim, você precisa. E se você alterar o valor da variável dentro da instrução using, ainda é o valor original que é descartado.
Jon Skeet de

@JonSkeet Não foi possível entender se ainda é o valor original que foi descartado.
Orkhan Alikhanov

@OrkhanAlikhanov: O compilador basicamente pega uma cópia da variável no início da usinginstrução. Portanto, alterar o valor dessa variável dentro do bloco não altera qual objeto é descartado.
Jon Skeet

A propósito, deveria haver out messages.
Orkhan Alikhanov

0

Você deve passar uma variável para o parâmetro out. Você não precisa inicializar a variável antes de passá-la:

MyMessagesType messages;
myResult = MakeMyCall(inputParams, out messages); 

Normalmente, você pode simplesmente ignorar as 'mensagens' após a chamada - a menos que as 'mensagens' precisem ser descartadas por algum motivo, como o uso de recursos limitados do sistema, caso em que você deve chamar Dispose ():

messages.Dispose();

Se ele pode usar uma quantidade significativa de memória e vai permanecer no escopo por um tempo, provavelmente deve ser definido como nulo se for um tipo de referência ou para uma nova instância padrão se for um tipo de valor, para que o lixo o coletor pode recuperar a memória:

messages = null; // Allow GC to reclaim memory for reference type.

messages = new MyMessageType(); // Allow GC to reclaim memory for value type.

0

Nesse caso, criei um método de extensão genérico para ConcurrentDictionary que não tem nenhum método Delete ou Remove.

//Remove item from list and ignore reference to removed item
public static void TryRemoveIgnore<K,T>(this ConcurrentDictionary<K,T> dictionary, K key)
{
    T CompletelyIgnored;
    dictionary.TryRemove(key, out CompletelyIgnored);
}

Quando chamado de uma instância de ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.