125 votes

void en C# generics ?

J'ai une méthode générique qui prend une requête et fournit une réponse.

public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}

Mais je ne veux pas toujours obtenir une réponse à ma demande, et je ne veux pas toujours fournir des données de demande pour obtenir une réponse. Je ne veux pas non plus avoir à copier et coller des méthodes dans leur intégralité pour apporter des modifications mineures. Ce que je veux, c'est pouvoir le faire :

public Tre DoSomething<Tres>(Tres response)
{
    return DoSomething<Tres, void>(response, null);
}

Est-ce possible 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.

127voto

dasblinkenlight Points 264350

Vous ne pouvez pas utiliser void mais vous pouvez utiliser object Le problème, c'est qu'il s'agit d'un petit désagrément parce que le candidat à l'immigration est un homme d'affaires. void doivent renvoyer null mais si cela permet d'unifier votre code, ce n'est pas cher payé.

Cette incapacité à utiliser void en tant que type de retour est au moins partiellement responsable d'une scission entre le Func<...> y Action<...> familles des délégués génériques : s'il avait été possible de revenir void , tous Action<X,Y,Z> deviendrait simplement Func<X,Y,Z,void> . Malheureusement, cela n'est pas possible.

105voto

Jon Skeet Points 692016

Non, malheureusement pas. Si void était un "vrai" type (comme unit en fa# La vie serait beaucoup plus simple à bien des égards. En particulier, nous n'aurions pas besoin de l'outil Func<T> y Action<T> familles - il n'y aurait que des Func<void> au lieu de Action , Func<T, void> au lieu de Action<T> etc.

Cela simplifierait également l'asynchronisme - il n'y aurait plus besoin de l'élément non générique Task Nous n'aurions qu'un seul type de Task<void> .

Malheureusement, ce n'est pas ainsi que fonctionnent les systèmes de types C# ou .NET...

29voto

1922 Points 1946

Voici ce que vous pouvez faire. Comme l'a dit @JohnSkeet, il n'y a pas de type d'unité en C#, alors faites-le vous-même !

public sealed class ThankYou {
   private ThankYou() { }
   private readonly static ThankYou bye = new ThankYou();
   public static ThankYou Bye { get { return bye; } }
}

Désormais, vous pouvez toujours utiliser Func<..., ThankYou> au lieu de Action<...>

public ThankYou MethodWithNoResult() {
   /* do things */
   return ThankYou.Bye;
}

Ou utilisez un produit déjà fabriqué par l'équipe Rx : http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx

19voto

Jeppe Stig Nielsen Points 17887

Vous pouvez simplement utiliser Object comme d'autres l'ont suggéré. Ou bien Int32 dont j'ai pu constater l'utilité. L'utilisation Int32 introduit un numéro "fictif" (utiliser 0 ), mais au moins vous ne pouvez pas mettre n'importe quel objet gros et exotique dans un Int32 (les structures sont scellées).

Vous pouvez également écrire votre propre type "void" :

public sealed class MyVoid
{
  MyVoid()
  {
    throw new InvalidOperationException("Don't instantiate MyVoid.");
  }
}

MyVoid sont autorisées (il ne s'agit pas d'une classe statique), mais elles ne peuvent être que null . Le constructeur d'instance est privé (et si quelqu'un essaie d'appeler ce constructeur privé par réflexion, une exception sera levée).


Depuis l'introduction des tuples de valeurs (2017, .NET 4.7), il est peut-être naturel d'utiliser la structure ValueTuple (le 0-tuple, la variante non générique) au lieu d'un tel MyVoid . Son instance a un ToString() qui renvoie "()" de sorte qu'il ressemble à un zéro-tuple. Dans la version actuelle de C#, vous ne pouvez pas utiliser les jetons () dans le code pour obtenir une instance. Vous pouvez utiliser default(ValueTuple) ou simplement default (lorsque le type peut être déduit du contexte).

8voto

Eske Rahn Points 91

J'aime l'idée d'Aleksey Bykov ci-dessus, mais elle pourrait être un peu simplifiée

public sealed class Nothing {
    public static Nothing AtAll { get { return null; } }
}

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 très utile pour les classes typées.

Par exemple, si le type n'est utilisé que pour décrire les arguments d'une procédure/fonction transmise en tant qu'argument à une méthode, et qu'il ne prend lui-même aucun argument.

(Vous devrez toujours créer une enveloppe fictive ou autoriser un "Rien" facultatif. Mais IMHO l'utilisation de la classe est agréable avec myClass<Nothing> )

void myProcWithNoArguments(Nothing Dummy){
     myProcWithNoArguments(){
}

o

void myProcWithNoArguments(Nothing Dummy=null){
    ...
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X