56 votes

Pourquoi n'Essayez-Catch besoin d'accolades

Juste par curiosité: Pourquoi est la syntaxe pour essayer de l'attraper en C# (Java aussi?) codé en dur pour plusieurs états? Pourquoi ne pas la langue de permettre:

int i;
string s = DateTime.Now.Seconds % 2 == 1 ? "1" : "not 1";
try
   i = int.Parse(s);
catch
   i = 0;

L'exemple est trivial seulement. Je sais qu'il y a int.TryParse.

76voto

Mark Schultheiss Points 13110

Considérez le fait qu'il y a vraiment trois (ou plus) des blocs de code en jeu ici:

try {}
catch (myexcption)
{}
catch (myotherexception)
{}
finally
{}

Gardez à l'esprit que ces sommes dans le cadre d'un contexte plus large, et les exceptions sont pas pris potentually pris plus haut dans la pile.

À noter que c'est essentiellement la même chose que construire une classe qui possède également l' {} de la structure.

Dire, par exemple, vous pourriez avoir:

try
try
if (iAmnotsane)
beatMe(please);
catch (Exception myexception)
catch (myotherexception)
logerror("howdy")
finally

MAINTENANT n'est que la deuxième capture appartiennent à la première ou à la deuxième essayer? Quel est le enfin? DONC, vous voyez l'option/plusieurs parties font l'obligation.

50voto

Eric Lippert Points 300275

Mise à JOUR: Cette question a fait l'objet de mon blog le 4 décembre 2012. Il y a un certain nombre de commentaires perspicaces sur le blog de ce que vous pourriez également être intéressé par. Merci pour la grande question!


Comme d'autres l'ont noté, le projet de fonctionnalité introduit des ambiguïtés qui sont source de confusion. J'étais curieux de voir si il y avait d'autres justifications de la décision de ne pas soutenir la fonction, donc j'ai vérifié la langue des design notes archive.

Je ne vois rien dans la langue de design notes archive qui justifie cette décision. Pour autant que je sais, C# est-il de cette façon parce que c'est la façon dont d'autres langues avec la même syntaxe que le faire, et ils le font de cette façon en raison du problème de l'ambiguïté.

J'ai appris quelque chose d'intéressant. Dans la conception initiale de C# il n'y a pas de try-catch-finally! Si vous voulais essayer avec une prise et un enfin alors vous avez dû écrire:

try
{
  try
  {
      XYZ();
  }
  catch(whatever)
  {
     DEF();
  }
}
finally
{
  ABC();
}

qui, sans surprise, est exactement la façon dont le compilateur analyse try-catch-finally; il se contente de il se décompose en try-catch à l'intérieur de essayez-enfin, lors de la première analyse et prétend que ce que vous avez dit dans la première place.

9voto

kidjan Points 1028

Plus ou moins, c'est un jeu sur le balançant d'autre problème.

Par exemple,

if( blah )
    if ( more blah )
        // do some blah
else
    // no blah I suppose

Sans accolades, le reste est ambigu, car vous ne savez pas si elle est associée à la première ou à la seconde si l'instruction. Donc, vous avez à revenir sur un compilateur convention (par exemple en Pascal ou en C, le compilateur suppose le balançant d'autre est associée à la plus proche si l'état) afin de résoudre l'ambiguïté, ou de ne pas le compiler entièrement si vous ne souhaitez pas autoriser une telle ambiguïté dans la première place.

De même,

try
    try
        // some code that throws!
catch(some blah)
    // which try block are we catching???
catch(more blah )
    // not so sure...
finally
    // totally unclear what try this is associated with.

Vous pourriez résoudre avec une convention, où les blocs catch sont toujours associés avec le plus proche d'essayer, mais je trouve cette solution permet en général de programmeurs à écrire le code qui est potentiellement dangereux. Par exemple, en C, ceci:

if( blah )
    if( more blah )
        x = blah;
    else
        x = blahblah;

...est de savoir comment le compilateur pourrait interpréter cette si/si/d'autre bloc. Cependant, il est également tout à fait légitime de vis de votre mise en retrait et à écrire:

if( blah )
    if( more blah )
        x = blah;
else
    x = blahblah;

...qui fait désormais apparaître comme l'autre est associée à l'extérieur si la déclaration, alors qu'en fait, il est associé à l'intérieure si l'instruction en raison de C conventions. Donc, je pense que exigeant que les accolades va un long chemin vers la résolution de l'ambiguïté et de prévention plutôt sournois bug (ces sortes de questions peuvent être facile à manquer, même au cours de l'inspection de codes). Des langages comme python n'ont pas ce problème car l'indentation et les espaces en question.

9voto

Pat Leahy Points 1433

Si l'on suppose que les concepteurs du C# tout simplement choisir d'utiliser la même syntaxe que C++, la question devient alors pourquoi sont croisillons nécessaire avec de simples déclarations de blocs try et catch en C++. La réponse est simple, Bjarne Stroustrup la pensée, la syntaxe est plus facile à expliquer.

Dans La Conception et l'Évolution de C++ Stroustrup écrit:

"Le mot-clé essayez est complètement redondant et sont donc les accolades {}, sauf lorsque plusieurs états sont effectivement utilisés dans un essai de bloc ou un gestionnaire."

Il continue à donner un exemple où le mot-clé essayez et { } ne sont pas nécessaires. Il écrit ensuite:

"Cependant, j'ai trouvé ce si difficile à expliquer que la redondance a été introduit pour économiser de l'assistance du personnel de confondre les utilisateurs."

Référence: Stroustrup, Bjarne (1994). La Conception et l'Évolution de C++. Addison-Wesley.

1voto

Albin Sunnanbo Points 30722

Le premier pense que je peux penser, c'est que les accolades créer un bloc avec sa propre portée des variables.

Regardez le code suivant

try
{
    int foo = 2;
}
catch (Exception)
{
    Console.WriteLine(foo); // The name 'foo' does not exist in the current context
}

foo n'est pas accessible dans le bloc catch en raison de la variable de portée. Je pense que cela rend plus facile de raisonner sur de savoir si une variable a été initialisée avant de les utiliser ou pas.

Comparer avec ce code

int foo;
try
{
    foo = 2;
}
catch (Exception)
{
    Console.WriteLine(foo); // Use of unassigned local variable 'foo'
}

ici, vous ne pouvez pas garantir que foo est initialisé.

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