67 votes

Est-il possible de ne pas gérer la valeur renvoyée d'une méthode C #? Quelle est la bonne pratique dans cet exemple?

Par curiosité...ce qui se passe lorsque nous appelons une méthode qui retourne une certaine valeur, mais nous n'avons pas utiliser/manipuler? Et nous nous attendons aussi que, parfois, cette valeur retournée peut être vraiment grand. Lorsque cette valeur va? Est-il créé? Si elle est, il y a des problèmes de performances ou d'autres problèmes qui peuvent survenir? (quelle est la meilleure pratique dans ce genre de situation?)

Disons que nous avons méthode qui effectue certaines opérations de base de données (insertion, mise à jour) et retourne des données dans l'objet DataTable. Et je sais aussi que cet objet DataTable pourrait être vraiment grand, parfois:

public static Datatable InsertIntoDB(...) 
{
      // executing db command, getting values, creating & returning Datatable object...
      ...
      return myDataTable;
}

Et puis, lorsque cette méthode est utilisée, il est appelé comme celles-ci:

DataTable myDataTable = InsertIntoDB(...);
// this Datatable object is handled in some way

Mais parfois simplement comme ceci:

InsertIntoDB(...);
// returned value not handled; Problem???

Sur ma première pensée, il pense que le système est assez intelligent pour voir la valeur de retour est ignorée et ne cause pas de problèmes (il est simplement sorti) mais je veux être sûr et d'entendre des explications plus détaillées de la part de quelqu'un qui est plus expérimenté dans ce domaine que moi.

96voto

Steve Morgan Points 9296

La valeur retournée (ou de référence, si c'est un type de référence) est poussé sur la pile, puis sauté à nouveau.

Pas de biggy.

Si la valeur de retour n'est pas pertinente, vous pouvez faire en toute sécurité.

Mais assurez-vous qu'il n'est pas pertinent, juste au cas où.

Voici un code:

    static string GetSomething()
    {
        return "Hello";
    }

    static void Method1()
    {
        string result = GetSomething();
    }

    static void Method2()
    {
        GetSomething();
    }

Si l'on regarde le IL:

Method1:

.locals init ([0] string result)
IL_0000:  nop
IL_0001:  call       string ConsoleApplication3.Program::GetSomething()
IL_0006:  stloc.0
IL_0007:  ret

Method2:

IL_0000:  nop
IL_0001:  call       string ConsoleApplication3.Program::GetSomething()
IL_0006:  pop
IL_0007:  ret

Exactement le même nombre d'instructions. Dans Method1, la valeur est stockée dans les locaux de la chaîne de résultat (stloc.0), qui est supprimé quand elle est hors de portée. Dans Method2, la pop opération simplement retire de la pile.

Dans votre cas, de retour quelque chose de vraiment grand", que des données ont déjà été créés et la méthode renvoie une référence à elle; et non les données. Dans Method1(), la référence est affecté à la variable locale et le ramasse-miettes de la ranger après la variable a disparu hors de portée (la fin de la méthode dans ce cas). Dans Method2(), le garbage collector peut se mettre au travail, en tout temps après la référence a été sauté par la pile.

En ignorant la valeur de retour, si ce n'est pas vraiment nécessaire, le garbage collector peut potentiellement obtenir de travailler plus rapidement et de libérer de la mémoire qui vous a été attribué. Mais il y a très peu (certainement dans ce cas), mais avec une méthode longue, de s'accrocher à des données pourrait être un problème.

Mais à présent-et de loin la chose la plus importante est de s'assurer que la valeur de retour que vous êtes ignorant n'est pas quelque chose que vous devriez être en agissant sur.

33voto

Jon Skeet Points 692016

EDIT: Adoucie la langue très légèrement, et clarifié.

C'est rarement une bonne idée d'ignorer la valeur de retour, dans mon expérience - au moins dans les cas où les valeurs de retour sont là pour transmettre de nouvelles informations au lieu d'être simplement pour des raisons de commodité.

Un exemple où je l'ai vu être d'accord:

int foo;
int.TryParse(someText, out foo);

// Keep going

Ici, foo sera 0 si someText "0", ou il n'a pas pu être analysée. Nous ne se soucient pas ce qui était le cas , auquel cas la valeur de retour de la méthode est pertinent pour nous.

Un autre exemple est dans un dictionnaire - supposons que vous essayez de compter le nombre d'occurrences de chaque chaîne. Vous pouvez utiliser:

int count;
dictionary.TryGetValue(word, out count);
dictionary[word] = count + 1;

Si le mot n'était pas dans le dictionnaire pour commencer, c'est équivalent à l'existence d'un nombre de 0, ce qui est déjà arriver comme un résultat de l'appel d' TryGetValue.

Comme un contre-exemple, en ignorant la valeur retournée par Stream.Read (et en supposant qu'il a réussi à lire toutes les données que vous avez demandé) est une erreur commune.

Si vous n'avez pas besoin de la valeur de retour et il aura fallu beaucoup d'efforts pour le calculer, il peut être intéressant de regarder pour quelque chose qui permettra d'atteindre le même souhaité effets secondaires sans le calcul, mais il n'y a pas de supplément de rendement implication. Je serais plus inquiet au sujet de la justesse de ignorant la valeur de retour de la performance.

EDIT: d'Autres exemples où c'est ok pour ignorer la valeur de retour:

  • Certains couramment interfaces, y compris StringBuilder; tandis que, StringBuilder.Append(x).Append(y); utilise la première valeur de retour pour le second appel, très souvent, la valeur de retour d'un appel sera ignoré, par exemple lors de l'ajout dans une boucle
  • Certains appels de recouvrement peut donner les valeurs de retour qui sont parfois ignorées, par exemple, HashSet<T>.Add qui indique si la valeur a été effectivement ajouté, ou s'il était déjà présent. Parfois, vous n'avez pas de soins.

Mais, pour la grande majorité du temps, en ignorant la valeur de retour d'une méthode indique qu'il est en fait plus que vous en avez besoin.

9voto

Justin Points 42106

Du point de vue de la gestion de la mémoire, c’est très bien - si la fonction d’appel ne l’utilise pas, elle sort de la portée et est récupérée.

Dans ce cas particulier, DataTable met en œuvre IDisposable sorte que ce n'est pas tout amende à 100%:

Si l'objet retourné implémente IDisposable alors c'est une bonne idée de le disposer, par exemple:

 using (var retVal = InsertIntoDB(...))
{
    // Could leave this empty if you wanted
}
 

4voto

Jalal Aldeen Saa'd Points 9120

Il dépend de la valeur retournée de soi.

Le compilateur va générer de la valeur à l'appelant de la méthode, de Sorte que si la valeur est IDispolable ou exposer Close méthode ou si elle a des ressources qui devraient être libérés, alors vous ne devez pas l'ignorer et de le disposer correctement, sinon vous risquez de souffrir de problèmes et les fuites de mémoire..

Par exemple, si la valeur retournée est un FileStream et que vous n'avez pas de fermer le flux de données, le fichier peut ne pas fermée jusqu'à ce que votre application est terminée, plus de plus si votre application essayez d'ouvrir à nouveau le fichier, il peut jeter l'exception qui indique que Le fichier est utilisé par un autre processus". Donc vous devez être prudent sur ce genre d'objet retourné et ne jamais l'ignorer!

2voto

Sani Huttunen Points 10433

C'est totalement correct d'ignorer la valeur de retour.

Toutefois. La conception architecturale est, IMHO, pas bonne. Une méthode d'insertion ne doit rien renvoyer (autre que MAYBE true ou false en cas de succès ou d'échec). Si vous devez obtenir un nouvel ensemble de données mis à jour, vous devez le demander, c'est-à-dire appeler une autre méthode pour le faire.

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