web-dev-qa-db-fra.com

Pourquoi C # ne me permet-il pas d'appeler une méthode void dans le cadre de l'instruction return?

Je suis curieux de savoir s'il existe une raison légitime pour laquelle C # ne prend pas en charge l'appel d'une méthode void dans le cadre de l'instruction return lorsque le type de retour de la méthode appelante est également vide.

public void MethodA() 
{ 
    return; 
}

public void MethodB() 
{
    return MethodA();
}

Donc, nous verrions normalement ceci:

public void MethodMeh() 
{
    if (expression) 
    {
        MethodA();
        return;
    }

    // Do more stuff
}

... quand nous pourrions utiliser ceci à la place:

public void MethodAwesome() 
{
    if (expression) 
        return MethodA();

    // Do more stuff
}

Est-ce une limitation de langage due à la façon dont C # gère le vide?

38
Matt Beckman

Parce que c'est simplement la voie le langage est défini .

Une méthode peut utiliser des instructions return pour renvoyer le contrôle à son appelant. Dans une méthode renvoyant void, return, les instructions ne peuvent pas spécifier une expression. Dans une méthode renvoyant non_void, return doivent inclure une expression qui calcule la valeur de retour.

C'est une décision arbitraire (vraisemblablement prise pour la compatibilité avec ANSI C et ses autres descendants), et d'autres langages font les choses différemment.

Par exemple, en Python, toutes les fonctions renvoient une valeur. Si vous exécutez une instruction return sans valeur ou si vous laissez le contrôle atteindre la fin de la fonction, c'est comme si vous aviez écrit return None.

En revanche, Pascal limite la terminologie de function aux sous-programmes qui ont une valeur de retour; si vous ne voulez rien retourner, utilisez plutôt un procedure.

39
dan04

void est l'absence d'information; cela n'a aucun sens de le renvoyer. Ce n'est pas un type *, et ce n'est pas une valeur, contrairement à d'autres langues. Non, ce n'est pas vraiment une limitation.

* Eh bien, en quelque sorte, comme le souligne @Lucas. C’est un type d’information; il ne représente pas réellement un type au sens habituel. Vous ne pouvez pas en avoir un.

28
Ry-

Votre question concerne à peu près la différence entre le type void et le type unit (le plus souvent vu dans les langages fonctionnels comme F #) .

Fondamentalement, void n'est pas un type réel. Bien qu'il y ait System.Void à des fins de réflexion, vous ne pouvez pas utiliser void dans la plupart des endroits où vous pouvez utiliser un vrai type: vous ne pouvez pas avoir une variable de type void et vous pouvez ' t l'utilise en générique (même s'il est capable d'écrire Func<void> serait parfois très utile).

En revanche, unit en F # est un type réel: il a une valeur (unique) (appelée ()), vous pouvez écrire l'équivalent de Func<void> (écrit unit -> unit, où le premier unit signifie "pas de paramètres", similaire à l'écriture de void dans la liste des paramètres en C) et vous pouvez avoir des variables de type unit. Par exemple:

let unitTest (f : unit -> unit) =
    let nothing : unit = f()
    ()

La dernière ligne montre en fait qu'en F #, vous devez parfois retourner explicitement unit.

7
svick

Ceci n'est pas autorisé selon la spécification de langue. Du 15.9.4 de l'ECMA-334 (soulignement le mien):

Une instruction return avec une expression ne peut être utilisée que dans un membre de fonction qui calcule une valeur, c'est-à-dire une méthode avec type de retour non-void, l'accesseur get d'une propriété ou un indexeur, ou un opérateur défini par l'utilisateur.

4
AlexD

Cela revient aux choix du concepteur de langage.

Du point de vue du type, void n'a pas de valeurs énumérables, donc cela n'a pas de sens de renvoyer une valeur de type "void"? nul est l'absence de type ou de contexte d'évaluation.

Vous ne pouvez pas instancier ou retourner "void" en C # ou Java.

Si vous pouviez le faire, vous devriez également pouvoir dire:

 void i;
 i = (what would go here?)
 return i;

Ce qui précède n'a aucun sens, mais est équivalent à ce que vous proposez.

En fin de compte, proposer que nous puissions propager un contexte de retour vide avec l'instruction de retour est simplement une question de sucre syntaxique, qui revient aux choix faits par le concepteur de langage.

La spécification du langage C # http://msdn.Microsoft.com/en-us/library/aa691305 (v = vs.71) .aspx (section 7.1) dit

Rien. Cela se produit lorsque l'expression est une invocation d'une méthode avec un type de retour void. Une expression classée comme rien n'est valable que dans le contexte d'une expression-instruction (section 8.6).

D'un autre côté, le concepteur C++ a en fait choisi d'autoriser uniquement la construction que vous proposez, mais c'était spécifiquement pour l'uniformité syntaxique dans les modèles. En C++, le type de retour d'une fonction de modèle peut être un paramètre de modèle. (Stroustrop C++ Programming Language p 148) Sans cela, il y aurait des cas courants qui se compileraient pour tous les types, mais pas pour les vides, comme les appels de fonction imbriqués de type T. Pour cette raison, ce qui suit est C++ valide:

void B() {
  return;
}

void A() {
  return B(); // legal C++ - doesn't yield a value
}

// But even in C++ the next line is illegal
int i = A();

Ainsi, l'expression de déclaration "return B ();" où B est une fonction void n'est qu'un raccourci pour "B (); return;" et ne produit pas réellement une valeur , car il n'existe pas de valeur nulle.

4
codenheim

J'ai une supposition sur une raison légitime à cela.

Lorsque le compilateur voit une expression, il essaie de la faire correspondre à quelque chose d'une liste d'expressions connues. On pourrait dire qu'il existe deux types d'instructions commençant par return:

  1. return exprexpr est une expression attribuable au type de retour déclaré de la méthode conteneur
  2. return sans rien d'autre

Ce sont des déclarations entièrement différentes, même si elles se ressemblent. Mais l'un peut se compile dans l'autre, dans certains cas (tout comme foreach se compile en while plus des trucs). Ainsi, vous pouvez ajouter une règle qui dit que return expr Se compile vers ce que expr; return; Compile, chaque fois que expr est déterminé comme étant sans type de retour (c'est-à-dire void).

Mais alors, les implémenteurs des compilateurs C # devraient autoriser toutes les expressions à ne pas avoir de type de retour, alors que normalement seules instructions sont autorisées à ne pas avoir de type de retour. S'ils le faisaient, ils devraient alors interdire manuellement les expressions sans type là où un type réel est requis. Par exemple, dans les expressions qui agissent comme arguments pour un appel de fonction MyMethod(1, 2, SomethingVoid()), le compilateur devrait en outre vérifier si l'une de ces expressions ne renvoie pas de type. Et pour chaque nouveau type d'expression ajouté à C # à l'avenir, la même vérification devrait être ajoutée.

Ce qui précède est possible, mais cela se produirait sans autre raison que de permettre aux expressions non-instruction dans l'arbre de syntaxe abstraite (qui est généré lors de la compilation) de n'avoir aucun type de retour, et ce serait le cas juste pour permettre une syntaxe mineure structure - et qui a une alternative qui n'est plus (en frappes) à taper et peut-être plus claire à lire.

En fin de compte, cela ne semble pas en valoir la peine.

Le titre de votre question ne semble pas être couvert par les réponses, même si elles parviennent à la bonne chose. Vous êtes question du titre

Pourquoi C # ne prend-il pas en charge le retour d'une méthode avec un type de retour vide

En fait, C # le permet, mais pas dans le format que vous essayez. L'utilisation du mot clé void comme d'autres l'ont répondu signifie que la méthode ne renvoie rien. Si vous souhaitez renvoyer une méthode qui ne renvoie rien, vous devez faire quelque chose comme ceci:

public Action MethodExample()
{
    return () => { Console.WriteLine("Hello World!"); };
}

Ensuite, un simple appel vous donnera cette action:

var action = MethodExample();
action(); // prints Hello World
2
Ian

Un vide est vide. Le mot clé void dans le langage C # indique qu'une méthode ne renvoie rien. Lorsqu'une méthode void est invoquée, elle n'a aucun résultat et aucune variable ne peut être affectée.

voir cette explication

1
bumbumpaw