Question

Cette question fait suite à Comment indiquer qu'un La méthode a échoué . Le modèle xxx () Tryxxx () est quelque chose qui peut être très utile dans de nombreuses bibliothèques. Je me demande quel est le meilleur moyen d’offrir les deux implémentations sans dupliquer mon code.

Quel est le meilleur:

public int DoSomething(string a)
{
     // might throw an exception
}
public bool TrySomething(string a, out result)
{
    try
    {
        result = DoSomething(a)
        return true;
    }
    catch (Exception)
    {
        return false;
    }

ou

public int DoSomething(string a)
{
     int result;
     if (TrySomething(a, out result))
     {
         return result;
     }
     else
     {
         throw Exception(); // which exception?
     }
}
public bool TrySomething(string a, out result)
{
    //...
}

Je supposerais instinctivement que le premier exemple est plus correct (vous savez exactement quelle exception s'est produite), mais le test / capture ne pourrait-il pas être trop coûteux? Existe-t-il un moyen de détecter l’exception dans le deuxième exemple?

Était-ce utile?

La solution

Faire de TrySomething juste attraper et avaler l'exception est une très mauvaise idée. Le motif TryXXX a pour objectif d’éviter toute atteinte aux performances due aux exceptions.

Si l'exception ne nécessite pas beaucoup d'informations, vous pouvez demander à la méthode DoSomething d'appeler simplement TrySomething et de lancer une exception en cas d'échec. Si vous avez besoin de détails dans l'exception, vous aurez peut-être besoin de quelque chose de plus élaboré. Je n'ai pas encore déterminé à quel moment l'essentiel des exceptions en termes de performances a trait aux performances. Si c'est le lancement plutôt que la création, vous pouvez écrire une méthode privée qui possède une signature similaire à TrySomething, mais qui renvoie une exception ou une valeur null:

public int DoSomething(string input)
{
    int ret;
    Exception exception = DoSomethingImpl(input, out ret);
    if (exception != null)
    {
        // Note that you'll lose stack trace accuracy here
        throw exception;
    }
    return ret;
}

public bool TrySomething(string input, out int ret)
{
    Exception exception = DoSomethingImpl(input, out ret);
    return exception == null;
}

private Exception DoSomethingImpl(string input, out int ret)
{
    ret = 0;
    if (input != "bad")
    {
        ret = 5;
        return null;
    }
    else
    {
        return new ArgumentException("Some details");
    }
}

Chronométrez cela avant de vous y engager!

Autres conseils

J'utilise habituellement ce modèle. Dépend de la façon dont la méthode Internal est implémentée pour déterminer si cela a un sens ou non. Si vous devez utiliser des blocs d’attrape conditionnels, cela peut devenir un peu méchant ...

public object DoSomething(object input){
  return DoSomethingInternal(input, true);
}

public bool TryDoSomething(object input, out object result){
  result = DoSomethingInternal(input, false);
  return result != null;
}

private object DoSomethingInternal(object input, bool throwOnError){
  /* do your work here; only throw if you cannot proceed and throwOnError is true */
}

Le premier exemple est correct si vous voulez capturer l'exception et ne rien faire d'autre que retourner false.

Vous pouvez modifier la méthode TryShow quelque chose comme ci-dessous.

public bool TrySomething(string a, out result, bool throwException)
{
  try
  {
    // Whatever
  }
  catch
  {
    if(throwException)
    {
      throw;
    }
    else
    {
      return false;
    }
  }

}

public bool TrySomething(string a, out result)
{
  return TrySomething(a, out result, false);
}

AlorsQuelque chose ressemblerait à

public int DoSomething(string a)
{
  int result;

  // This will throw the execption or 
  // change to false to not, or don't use the overloaded one.
  TrySomething(a, out result, true) 

  return result;      
}

Si vous ne voulez pas que TrySomething avec throwException soit exposé au public, vous pouvez en faire un membre privé.

Les exceptions peuvent coûter cher et vous pouvez effectuer une vérification RegEx sur la chaîne pour empêcher l’envoyer une. Cela dépend de ce que vous essayez de faire.

En supposant qu'il s'agisse de C #, je dirais le deuxième exemple

public bool TrySomething(string a, out result)
{
    try
    {
        result = DoSomething(a)
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}

Il imite le int.TryParse (chaîne s, out int result) intégré et, à mon avis, il est préférable de rester cohérent avec la langue / l'environnement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top