Comment utiliser le mot-clé throws de style Java en C #?


89

En Java, le throwsmot clé permet à une méthode de déclarer qu'elle ne gérera pas une exception seule, mais la lancera plutôt à la méthode appelante.

Existe-t-il un mot-clé / attribut similaire en C #?

S'il n'y a pas d'équivalent, comment pouvez-vous obtenir le même effet (ou un effet similaire)?

Réponses:


75

En Java, vous devez gérer une exception ou marquer la méthode comme une méthode susceptible de la lever à l'aide du throwsmot - clé.

C # n'a pas ce mot-clé ou un équivalent, comme en C #, si vous ne gérez pas d'exception, il bouillonnera, jusqu'à ce qu'il soit attrapé ou s'il n'est pas attrapé, il mettra fin au programme.

Si vous voulez le gérer, relancez, vous pouvez faire ce qui suit:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}

1
"ça va bouillonner", cela signifie-t-il que c'est équivalent à toutes les méthodes ayant une clause throws en Java?
Louis Rhys

1
@Louis RH - en quelque sorte. Cela signifie qu'une exception, si elle n'est pas gérée, remontera la chaîne d'appels à travers chaque fonction appelante jusqu'à ce qu'elle soit traitée.
Oded

1
@Louis RH pas complètement, cela signifierait que vous deviez attraper l'exception au moins dans votre main pour compiler le code. Parce que C # ne connaît pas les exceptions vérifiées, c'est à vous de les attraper, sinon ils atterriront simplement dans le runtime et interrompront votre code.
Johannes Wachter

1
@jwatcher: une méthode main peut aussi avoir une clause throw.
Louis Rhys

4
@AshishKamble - hein. Question d'opinion. La gestion des exceptions est différente dans .NET. Ne pensez pas que vous savez ce qui est «mieux».
Oded

105

L'op pose des questions sur l' équivalent C # de la throwsclause Java - pas sur le throwmot - clé. Ceci est utilisé dans les signatures de méthode en Java pour indiquer qu'une exception vérifiée peut être levée.

En C #, il n'y a pas d'équivalent direct d'une exception vérifiée Java. C # n'a pas de clause de signature de méthode équivalente.

// Java - need to have throws clause if IOException not handled
public void readFile() throws java.io.IOException {
  ...not explicitly handling java.io.IOException...
}

Se traduit par

// C# - no equivalent of throws clause exceptions are unchecked
public void ReadFile() 
{
  ...not explicitly handling System.IO.IOException...
}

30

Oui, c'est un ancien fil de discussion, mais je trouve fréquemment de vieux fils lorsque je cherche des réponses sur Google, alors j'ai pensé que j'ajouterais quelque chose d'utile que j'ai trouvé.

Si vous utilisez Visual Studio 2012, il existe un outil intégré qui peut être utilisé pour autoriser un équivalent "throws" de niveau IDE.

Si vous utilisez des commentaires de documentation XML , comme mentionné ci-dessus, vous pouvez utiliser la balise <exception> pour spécifier le type d'exception levée par la méthode ou la classe ainsi que des informations sur le moment et la raison de son déclenchement.

exemple:

    /// <summary>This method throws an exception.</summary>
    /// <param name="myPath">A path to a directory that will be zipped.</param>
    /// <exception cref="IOException">This exception is thrown if the archive already exists</exception>
    public void FooThrowsAnException (string myPath)
    {
        // This will throw an IO exception
        ZipFile.CreateFromDirectory(myPath);
    }

4
OP, ceci est votre réponse. Je suppose, mais JAVA throwsne signifie probablement rien pour le runtime, à part être informatif pour le développeur. De même, ce que @mvanella a souligné ici est la façon dont le C # fait exactement la même chose. Je suppose que vous savez déjà que cette "documentation xml" a un but plus important. Je sais que ce fil est vieux.
Hari Lubovac

En fait, Java ne fait pas de bulles d'exceptions à moins qu'il ne soit explicitement spécifié dans une throwsclause ou levé par une throwcommande. Cela signifie que si une RunTimeException se produit et n'est pas gérée dans la même méthode où elle se produit, l'exécution s'arrêtera là.
Pedro Lima

18

Voici une réponse à une question similaire que je viens de trouver sur bytes.com :

La réponse courte est non. Il n'y a pas d'exceptions vérifiées en C #. Le concepteur de la langue discute de cette décision dans cette interview:

http://www.artima.com/intv/handcuffs.html

Le plus proche que vous pouvez obtenir est d'utiliser les balises dans votre documentation XML et de distribuer les documents générés par NDoc avec votre code / assemblages afin que d'autres personnes puissent voir les exceptions que vous lancez (ce qui est exactement ce que MS fait dans la documentation MSDN). Cependant, vous ne pouvez pas compter sur le compilateur pour vous informer des exceptions non gérées, comme vous en avez peut-être l'habitude en java.


7

Après avoir parcouru la plupart des réponses ici, j'aimerais ajouter quelques réflexions.

  1. S'appuyer sur les commentaires de documentation XML et s'attendre à ce que les autres s'appuient sur est un mauvais choix. La plupart des codes C # que j'ai rencontrés ne documentent pas les méthodes complètement et de manière cohérente avec les commentaires de documentation XML. Et puis il y a le plus gros problème que sans les exceptions vérifiées en C #, comment pourriez-vous documenter toutes les exceptions que votre méthode lève pour que votre utilisateur d'API sache comment les gérer toutes individuellement? N'oubliez pas que vous ne connaissez que ceux que vous vous lancez avec le mot-clé throw dans votre implémentation. Les API que vous utilisez dans votre implémentation de méthode peuvent également lancer des exceptions dont vous ne connaissez pas, car elles peuvent ne pas être documentées et que vous ne les gérez pas dans votre implémentation, elles exploseront donc face à l'appelant de votre méthode. En d'autres termes,

  2. Andreas a lié une interview avec Anders Hejlsberg dans les réponses ici sur les raisons pour lesquelles l'équipe de conception C # a décidé de ne pas vérifier les exceptions. La réponse ultime à la question originale est cachée dans cet entretien:

Les programmeurs protègent leur code en écrivant «try finally», donc ils reculeront correctement si une exception se produit, mais ils ne sont pas réellement intéressés par la gestion des exceptions.

En d'autres termes, personne ne devrait être intéressé par le type d'exception auquel on peut s'attendre pour une API particulière, car vous allez toujours les attraper partout. Et si vous voulez vraiment vous soucier des exceptions particulières, c'est à vous de décider comment les gérer et non à quelqu'un qui définit une signature de méthode avec quelque chose comme le mot-clé Java throws, ce qui oblige un utilisateur d'API à gérer des exceptions particulières.

-

Personnellement, je suis déchiré ici. Je suis d'accord avec Anders que le fait de vérifier les exceptions ne résout pas le problème sans ajouter de nouveaux problèmes différents. Tout comme avec les commentaires de la documentation XML, je vois rarement du code C # avec tout ce qui est enveloppé dans des blocs try finally. Il me semble que c'est en effet votre seule option et quelque chose qui semble être une bonne pratique.


3

En fait, ne pas avoir vérifié les exceptions en C # peut être considéré comme une bonne ou une mauvaise chose.

Je considère moi-même que c'est une bonne solution car les exceptions vérifiées vous posent les problèmes suivants:

  1. Les exceptions techniques fuient vers la couche métier / domaine car vous ne pouvez pas les gérer correctement au bas niveau.
  2. Ils appartiennent à la signature de méthode qui ne joue pas toujours bien avec la conception d'API.

Pour cette raison, dans la plupart des applications plus volumineuses, vous verrez souvent le modèle suivant lorsque coché Des exceptions se produisent:

try {
    // Some Code
} catch(SomeException ex){
    throw new RuntimeException(ex);
}

Ce qui signifie essentiellement émuler la façon dont C # / .NET gère toutes les exceptions.


Je ne peux pas imaginer comment les exceptions vérifiées se mélangeraient avec les lambdas!
Gabe

@Gabe: Je suis sûr que vous pourriez trouver un concept qui vous permet de les mélanger, mais comme je l'ai dit, les exceptions vérifiées sont en Java aussi généralement pas de bonnes pratiques, en particulier dans les applications plus complexes. Donc c'est bien qu'ils ne soient pas là en C #.
Johannes Wachter

3

Vous demandez à ce sujet:

Relancer une exception

public void Method()
{
  try
  {
      int x = 0;
      int sum = 100/x;
  }
  catch(DivideByZeroException e)
  {
      throw;
  }
}

ou

static void Main() 
    {
        string s = null;

        if (s == null) 
        {
            throw new ArgumentNullException();
        }

        Console.Write("The string s is null"); // not executed
    }

3
+1 pour l'utilisation throw. En l'utilisant, la trace de la pile ne sera pas perdue.
Giuseppe Accaputo

2

Il existe quelques similitudes éphémères entre le .Net CodeContract EnsuresOnThrow<>et le throwsdescripteur java , en ce sens que les deux peuvent signaler à l'appelant le type d'exception qui pourrait être déclenchée à partir d'une fonction ou d'une méthode, bien qu'il existe également des différences majeures entre les 2:

  • EnsuresOnThrow<>va au-delà du simple énoncé des exceptions qui peuvent être levées, mais stipule également les conditions dans lesquelles elles sont garanties d'être levées - cela peut être un code assez onéreux dans la méthode appelée si la condition d'exception n'est pas facile à identifier. Java throwsfournit une indication des exceptions qui pourraient être levées (c'est-à-dire que l'OMI, le focus dans .Net est à l'intérieur de la méthode qui contracte pour prouver le throw, alors qu'en Java, le focus se déplace vers l'appelant pour reconnaître la possibilité de l'exception).
  • .Net CC ne fait pas la distinction entre les exceptions vérifiées et non vérifiées de Java, bien que la section 2.2.2 du manuel CC mentionne

"utiliser des postconditions exceptionnelles uniquement pour les exceptions auxquelles un appelant doit s'attendre dans le cadre de l'API"

  • Dans .Net, l'appelant peut déterminer s'il doit ou non faire quoi que ce soit à l'exception (par exemple en désactivant les contrats). En Java, l'appelant doit faire quelque chose , même s'il ajoute un throwspour la même exception sur son interface.

Manuel des contrats de code ici


0

Si le but de la méthode c # est de lancer uniquement une exception (comme le dit le type de retour js), je recommanderais simplement de renvoyer cette exception. Voir l'exemple ci-dessous:

    public EntityNotFoundException GetEntityNotFoundException(Type entityType, object id)
    {
        return new EntityNotFoundException($"The object '{entityType.Name}' with given id '{id}' not found.");
    }

    public TEntity GetEntity<TEntity>(string id)
    {
        var entity = session.Get<TEntity>(id);
        if (entity == null)
            throw GetEntityNotFoundException(typeof(TEntity), id);
        return entity;
    }

0

Pour ceux qui se demandent, vous n'avez même pas besoin de définir ce que vous attrapez pour le transmettre à la méthode suivante. Dans le cas où vous voudriez que toute votre gestion des erreurs dans un thread principal, vous pouvez simplement tout attraper et le transmettre comme ceci:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.