Tengo un método genérico que toma una solicitud y proporciona una respuesta.
public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}
Pero no siempre quiero una respuesta para mi solicitud, y no siempre quiero alimentar los datos de la solicitud para obtener una respuesta. Tampoco quiero tener que copiar y pegar métodos en su totalidad para realizar cambios menores. Lo que quiero es poder hacer esto:
public Tre DoSomething<Tres>(Tres response)
{
return DoSomething<Tres, void>(response, null);
}
¿Es esto factible de alguna manera? Parece que usar void específicamente no funciona, pero espero encontrar algo análogo.
DoSomething(x);
en lugar dey = DoSomething(x);
Respuestas:
No puede usar
void
, pero puede usarobject
: es un pequeño inconveniente porque sus posiblesvoid
funciones deben regresarnull
, pero si unifica su código, debería ser un pequeño precio a pagar.Esta incapacidad para usar
void
como tipo de retorno es al menos parcialmente responsable de una división entre las familiasFunc<...>
yAction<...>
de los delegados genéricos: si hubiera sido posible regresarvoid
, todoAction<X,Y,Z>
sería simpleFunc<X,Y,Z,void>
. Desafortunadamente, esto no es posible.fuente
void
de esos métodos que podrían ser nulos, conreturn System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(void));
. Sin embargo, será un vacío en caja.void
en FP. Y hay buenas razones para usarlo. En F #, todavía .NET, tenemosunit
archivos.No, desafortunadamente no. Si
void
fuera un tipo "real" (comounit
en F # , por ejemplo) la vida sería mucho más simple en muchos sentidos. En particular, no necesitaríamos tanto a las familiasFunc<T>
como a lasAction<T>
familias, simplemente habría enFunc<void>
lugar deAction
, enFunc<T, void>
lugar de,Action<T>
etc.También simplificaría el async (no habría necesidad de un tipo no genérico
Task
en absoluto), simplemente lo haríamosTask<void>
.Desafortunadamente, esa no es la forma en que funcionan los sistemas de tipo C # o .NET ...
fuente
Unfortunately, that's not the way the C# or .NET type systems work...
Me estabas dando la esperanza de que tal vez las cosas pudieran funcionar así eventualmente. ¿Su último punto significa que no es probable que las cosas funcionen de esa manera?Esto es lo que puede hacer. Como dijo @JohnSkeet, no hay un tipo de unidad en C #, ¡así que hágalo usted mismo!
Ahora siempre puedes usar en
Func<..., ThankYou>
lugar deAction<...>
O use algo que ya haya hecho el equipo de Rx: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx
fuente
Install-Package System.Reactive.Core
Kthx.Bye;
Simplemente puede usarlo
Object
como otros han sugerido. OInt32
que he visto algún uso. El usoInt32
introduce un número "ficticio" (uso0
), pero al menos no puede poner ningún objeto grande y exótico en unaInt32
referencia (las estructuras están selladas).También puede escribir su propio tipo "vacío":
MyVoid
Se permiten referencias (no es una clase estática) pero solo pueden sernull
. El constructor de la instancia es privado (y si alguien intenta llamar a este constructor privado mediante la reflexión, se le lanzará una excepción).Dado que se introdujeron las tuplas de valor (2017, .NET 4.7), tal vez sea natural usar la estructura
ValueTuple
(la tupla 0, la variante no genérica) en lugar de talMyVoid
. Su instancia tiene unToString()
que devuelve"()"
, por lo que parece una tupla cero. A partir de la versión actual de C #, no puede usar los tokens()
en el código para obtener una instancia. En su lugar, puede usardefault(ValueTuple)
o solodefault
(cuando el tipo se puede inferir del contexto).fuente
Me gusta la idea de Aleksey Bykov anterior, pero podría simplificarse un poco
Como no veo ninguna razón aparente por la cual Nothing.AtAll no podría simplemente dar null
La misma idea (o la de Jeppe Stig Nielsen) también es excelente para usar con clases escritas.
Por ejemplo, si el tipo solo se usa para describir los argumentos de un procedimiento / función que se pasa como argumento a algún método, y él mismo no toma ningún argumento.
(Todavía necesitará hacer una envoltura ficticia o permitir un "Nada" opcional. Pero en mi humilde opinión, el uso de la clase se ve bien con myClass <Nothing>)
o
fuente
null
tiene la connotación de estar ausente o ausenteobject
. Tener un solo valor para unNothing
significa que nunca se parece a nada más.Nothing
almacenada en un campo estático privado y agregando un constructor privado. El hecho de que null todavía sea posible es molesto, pero eso se resolverá, con suerte con C # 8.void
, aunque es un tipo, solo es válido como un tipo de retorno de un método.No hay forma de evitar esta limitación de
void
.fuente
Lo que hago actualmente es crear tipos sellados personalizados con constructor privado. Esto es mejor que lanzar excepciones en el c-tor porque no tiene que llegar hasta el tiempo de ejecución para darse cuenta de que la situación es incorrecta. Es sutilmente mejor que devolver una instancia estática porque no tiene que asignar ni una sola vez. Es sutilmente mejor que devolver un valor nulo estático porque es menos detallado en el lado de la llamada. Lo único que puede hacer la persona que llama es dar un valor nulo.
fuente