J'ai une méthode générique qui prend une demande et fournit une réponse.
public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}
Mais je ne veux pas toujours une réponse à ma demande et je ne veux pas toujours alimenter les données de la demande pour obtenir une réponse. Je ne veux pas non plus avoir à copier et coller les méthodes dans leur intégralité pour apporter des modifications mineures. Ce que je veux, c'est pouvoir faire ceci:
public Tre DoSomething<Tres>(Tres response)
{
return DoSomething<Tres, void>(response, null);
}
Est-ce faisable d'une manière ou d'une autre? Il semble que l'utilisation spécifique de void ne fonctionne pas, mais j'espère trouver quelque chose d'analogue.
DoSomething(x);
au lieu dey = DoSomething(x);
Réponses:
Vous ne pouvez pas utiliser
void
, mais vous pouvez utiliserobject
: c'est un petit inconvénient car vos futuresvoid
fonctions doivent revenirnull
, mais si cela unifie votre code, cela devrait être un petit prix à payer.Cette incapacité à utiliser
void
comme type de retour est au moins partiellement responsable d'une scission entre lesFunc<...>
et lesAction<...>
familles de délégués génériques: s'il avait été possible de revenirvoid
, toutAction<X,Y,Z>
deviendrait simplementFunc<X,Y,Z,void>
. Malheureusement, ce n'est pas possible.la source
void
de ces méthodes prétendument nulles, avecreturn System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(void));
. Ce sera un vide fermé, cependant.void
dans FP. Et il y a de bonnes raisons de l'utiliser. En F #, toujours .NET, nous avonsunit
intégré.Non, malheureusement non. Si
void
c'était un type "réel" (commeunit
en F # , par exemple), la vie serait beaucoup plus simple à bien des égards. En particulier, nous n'aurions pas besoin à la fois des famillesFunc<T>
etAction<T>
- il y aurait juste à laFunc<void>
place deAction
,Func<T, void>
au lieu deAction<T>
etc.Cela simplifierait également l'async - il n'y aurait aucun besoin du type non générique
Task
- nous l'aurions simplement faitTask<void>
.Malheureusement, ce n'est pas ainsi que fonctionnent les systèmes de type C # ou .NET ...
la source
Unfortunately, that's not the way the C# or .NET type systems work...
Vous me donniez l'espoir que les choses pourraient éventuellement fonctionner comme ça. Votre dernier point signifie-t-il que nous ne pourrons probablement jamais faire fonctionner les choses de cette façon?Voici ce que vous pouvez faire. Comme @JohnSkeet l'a dit, il n'y a pas de type d'unité en C #, alors faites-le vous-même!
Maintenant, vous pouvez toujours utiliser à la
Func<..., ThankYou>
place deAction<...>
Ou utilisez quelque chose déjà créé par l'équipe Rx: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx
la source
Install-Package System.Reactive.Core
Kthx.Bye;
Vous pouvez simplement utiliser
Object
comme d'autres l'ont suggéré. OuInt32
dont j'ai vu une certaine utilité. UtiliserInt32
introduit un nombre "factice" (utilisation0
), mais au moins vous ne pouvez pas mettre de gros objet exotique dans uneInt32
référence (les structures sont scellées).Vous pouvez également écrire votre propre type "void":
MyVoid
les références sont autorisées (ce n'est pas une classe statique) mais ne peuvent l'être quenull
. Le constructeur d'instance est privé (et si quelqu'un essaie d'appeler ce constructeur privé par réflexion, une exception lui sera renvoyée).Depuis l'introduction de tuples de valeur (2017, .NET 4.7), il est peut-être naturel d'utiliser la structure struct
ValueTuple
(le 0-tuple, la variante non générique) au lieu d'un telMyVoid
. Son instance a unToString()
qui renvoie"()"
, donc elle ressemble à un zéro-tuple. À partir de la version actuelle de C #, vous ne pouvez pas utiliser les jetons()
dans le code pour obtenir une instance. Vous pouvez utiliserdefault(ValueTuple)
ou justedefault
(lorsque le type peut être déduit du contexte) à la place.la source
J'aime l'idée d'Aleksey Bykov ci-dessus, mais elle pourrait être un peu simplifiée
Comme je ne vois aucune raison apparente pour laquelle Nothing.AtAll ne pourrait pas simplement donner null
La même idée (ou celle de Jeppe Stig Nielsen) est également idéale pour une utilisation avec des classes typées.
Par exemple, si le type n'est utilisé que pour décrire les arguments d'une procédure / fonction passée comme argument à une méthode, et qu'il ne prend lui-même aucun argument.
(Vous aurez toujours besoin de créer un emballage factice ou d'autoriser un "Nothing" facultatif. Mais à mon humble avis, l'utilisation de la classe semble bien avec myClass <Nothing>)
ou
la source
null
a la connotation d'être manquant ou absentobject
. Avoir une seule valeur pour unNothing
signifie qu'il ne ressemble à rien d'autre.Nothing
stockée dans un champ statique privé et en ajoutant un constructeur privé. Le fait que null soit toujours possible est ennuyeux, mais cela sera résolu, espérons-le avec C # 8.void
, bien qu'un type, n'est valide que comme type de retour d'une méthode.Il n'y a aucun moyen de contourner cette limitation de
void
.la source
Ce que je fais actuellement, c'est créer des types scellés personnalisés avec un constructeur privé. C'est mieux que de lancer des exceptions dans le c-tor parce que vous n'avez pas besoin d'obtenir jusqu'à l'exécution pour comprendre que la situation est incorrecte. C'est subtilement mieux que de renvoyer une instance statique car vous n'avez pas à allouer une seule fois. C'est subtilement mieux que de renvoyer un null statique car il est moins détaillé du côté de l'appel. La seule chose que l'appelant peut faire est de donner null.
la source