Tenho um método genérico que recebe uma solicitação e fornece uma resposta.
public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}
Mas nem sempre quero uma resposta para minha solicitação e nem sempre quero alimentar os dados da solicitação para obter uma resposta. Também não quero ter que copiar e colar métodos inteiramente para fazer pequenas alterações. O que eu quero é ser capaz de fazer isso:
public Tre DoSomething<Tres>(Tres response)
{
return DoSomething<Tres, void>(response, null);
}
Isso é viável de alguma maneira? Parece que usar especificamente o vazio não funciona, mas espero encontrar algo análogo.
DoSomething(x);
em vez dey = DoSomething(x);
Respostas:
Você não pode usar
void
, mas pode usarobject
: é um pouco inconveniente porque suas supostasvoid
funções precisam retornarnull
, mas se isso unificar seu código, deverá ser um pequeno preço a pagar.Essa incapacidade de usar
void
como um tipo de retorno é pelo menos parcialmente responsável por uma divisão entre as famíliasFunc<...>
eAction<...>
dos delegados genéricos: se fosse possível retornarvoid
, todosAction<X,Y,Z>
se tornariam simplesFunc<X,Y,Z,void>
. Infelizmente, isto não é possível.fonte
void
daqueles métodos que seriam vazios, comreturn System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(void));
. No entanto, será um vazio encaixotado.void
no FP. E há boas razões para usá-lo. Em F #, ainda .NET, temos umunit
built-in.Não, infelizmente não. Se
void
fosse um tipo "real" (comounit
em F # , por exemplo), a vida seria muito mais simples de várias maneiras. Em particular, não precisaríamos das famíliasFunc<T>
eAction<T>
- haveria apenas emFunc<void>
vez deAction
, emFunc<T, void>
vez deAction<T>
etc.Isso também tornaria o async mais simples - não haveria necessidade do
Task
tipo não genérico - nós apenas teríamosTask<void>
.Infelizmente, não é assim que funcionam os sistemas do tipo C # ou .NET ...
fonte
Unfortunately, that's not the way the C# or .NET type systems work...
Você estava me deixando esperançoso de que talvez as coisas funcionassem assim eventualmente. Seu último ponto significa que provavelmente nunca faremos as coisas funcionarem dessa maneira?Aqui está o que você pode fazer. Como @JohnSkeet disse, não há tipo de unidade em C #, então faça você mesmo!
Agora você sempre pode usar em
Func<..., ThankYou>
vez deAction<...>
Ou use algo já feito pela equipe Rx: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx
fonte
Install-Package System.Reactive.Core
Kthx.Bye;
Você pode simplesmente usar
Object
como outros sugeriram. OuInt32
que vi alguma utilidade. UsarInt32
introduz um número "fictício" (usar0
), mas pelo menos você não pode colocar nenhum objeto grande e exótico em umaInt32
referência (as estruturas são lacradas).Você também pode escrever seu próprio tipo "vazio":
MyVoid
referências são permitidas (não é uma classe estática), mas só podem sernull
. O construtor da instância é privado (e se alguém tentar chamar este construtor privado por meio de reflexão, uma exceção será lançada para eles).Como as tuplas de valor foram introduzidas (2017, .NET 4.7), talvez seja natural usar a estrutura
ValueTuple
(a tupla 0, a variante não genérica) em vez de umaMyVoid
. Sua instância tem umToString()
que retorna"()"
, por isso parece uma tupla zero. A partir da versão atual do C #, você não pode usar os tokens()
no código para obter uma instância. Você pode usardefault(ValueTuple)
ou apenasdefault
(quando o tipo pode ser inferido a partir do contexto).fonte
Gosto da ideia de Aleksey Bykov acima, mas poderia ser um pouco simplificada
Como não vejo nenhuma razão aparente para que Nothing.AtAll não pudesse simplesmente dar null
A mesma ideia (ou a de Jeppe Stig Nielsen) também é ótima para uso com classes digitadas.
Por exemplo, se o tipo é usado apenas para descrever os argumentos para um procedimento / função passado como um argumento para algum método, e ele próprio não aceita nenhum argumento.
(Você ainda precisará fazer um invólucro fictício ou permitir um "Nada" opcional. Mas, IMHO, o uso da classe parece bom com myClass <Nada>)
ou
fonte
null
tem a conotação de estar ausente ou ausenteobject
. Ter apenas um valor paraNothing
significa que ele nunca se parece com qualquer outra coisa.Nothing
armazenada em um campo estático privado e adicionando um construtor privado. O fato de null ainda ser possível é irritante, mas será resolvido, esperançosamente com C # 8.void
, embora seja um tipo, só é válido como um tipo de retorno de um método.Não há como contornar essa limitação de
void
.fonte
O que eu faço atualmente é criar tipos selados personalizados com construtor privado. Isso é melhor do que lançar exceções no c-tor porque você não precisa chegar até o tempo de execução para descobrir que a situação está incorreta. É sutilmente melhor do que retornar uma instância estática, porque você não precisa alocar nem uma vez. É sutilmente melhor do que retornar um null estático porque é menos detalhado no lado da chamada. A única coisa que o chamador pode fazer é fornecer null.
fonte