107 votes

Déclaration de syntaxe de retour impair

Je sais que cela peut paraître étrange, mais je ne sais même pas comment rechercher cette syntaxe sur Internet et je ne suis pas sûr de ce que signifie exactement.

J'ai donc surveillé du code MoreLINQ, puis j'ai remarqué cette méthode.

 public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));

    return _(); IEnumerable<TSource> _()
    {
        var knownKeys = new HashSet<TKey>(comparer);
        foreach (var element in source)
        {
            if (knownKeys.Add(keySelector(element)))
                yield return element;
        }
    }
}
 

Quelle est cette déclaration de retour étrange? return _(); ?

107voto

Akash Kava Points 18026

C'est C# 7.0 qui prend en charge les fonctions locales....

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
       this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new 
           ArgumentNullException(nameof(source));
        if (keySelector == null) throw 
             new ArgumentNullException(nameof(keySelector));

        // This is basically executing _LocalFunction()
        return _LocalFunction(); 

        // This is a new inline method, 
        // return within this is only within scope of
        // this method
        IEnumerable<TSource> _LocalFunction()
        {
            var knownKeys = new HashSet<TKey>(comparer);
            foreach (var element in source)
            {
                if (knownKeys.Add(keySelector(element)))
                    yield return element;
            }
        }
    }

Actuel C# avec Func<T>

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
       this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new 
           ArgumentNullException(nameof(source));
        if (keySelector == null) throw 
             new ArgumentNullException(nameof(keySelector));

        Func<IEnumerable<TSource>> func = () => {
            var knownKeys = new HashSet<TKey>(comparer);
            foreach (var element in source)
            {
                if (knownKeys.Add(keySelector(element)))
                    yield return element;
            }
       };

        // This is basically executing func
        return func(); 

    }

Le truc est, _() est déclarée après il est utilisé, ce qui est parfaitement bien.

La pratique de l'utilisation de fonctions locales

L'exemple ci-dessus est juste une démonstration de la façon dont les méthodes peuvent être utilisées, mais le plus probable si vous allez à appeler la méthode une fois seulement, puis il n'est d'aucune utilité.

Mais dans l'exemple ci-dessus, comme mentionné dans les commentaires par Phoshi et Luaan, il y a un avantage de l'utilisation de la fonction locale. Depuis de fonction avec un taux de retour ne sera pas exécutée, à moins que quelqu'un effectue une itération, dans ce cas la méthode à l'extérieur de la fonction locale sera exécuté, et le paramètre validation sera effectuée même si personne ne sera à effectuer une itération de la valeur.

Plusieurs fois, nous avons répété code dans la méthode, permet de regarder cet exemple..

  public void ValidateCustomer(Customer customer){

      if( string.IsNullOrEmpty( customer.FirstName )){
           string error = "Firstname cannot be empty";
           customer.ValidationErrors.Add(error);
           ErrorLogger.Log(error);
           throw new ValidationError(error);
      }

      if( string.IsNullOrEmpty( customer.LastName )){
           string error = "Lastname cannot be empty";
           customer.ValidationErrors.Add(error);
           ErrorLogger.Log(error);
           throw new ValidationError(error);
      }

      ... on  and on... 
  }

Je pourrais optimiser avec...

  public void ValidateCustomer(Customer customer){

      void _validate(string value, string error){
           if(!string.IsNullOrWhitespace(value)){

              // i can easily reference customer here
              customer.ValidationErrors.Add(error);

              ErrorLogger.Log(error);
              throw new ValidationError(error);                   
           }
      }

      _validate(customer.FirstName, "Firstname cannot be empty");
      _validate(customer.LastName, "Lastname cannot be empty");
      ... on  and on... 
  }

24voto

Stuart Points 2009

Prenons l'exemple plus simple

 void Main()
{
    Console.WriteLine(Foo()); // Prints 5
}

public static int Foo()
{
    return _();

    // declare the body of _()
    int _()
    {
        return 5;
    }
}
 

_() est une fonction locale déclarée dans la méthode contenant l'instruction return.

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