2010-09-23 17 views
5

Je suis assez nouveau pour C# en provenance de Java, et je me demande s'il y a un moyen simple d'éviter la répétition de code impliquant des types primitifs comme celui-ci:C# Génériques pour éviter la répétition du code?


private Boolean AtLeastOneBufferItemIsNonZero(int[] Buffer) 
{ 
    Boolean result = false; 
    foreach (int Item in Buffer) 
    { 
     result = !(Item == (int)0); 
     if (result) break; 
    } 
    return result; 
} 

private Boolean AtLeastOneBufferItemIsNonZero(float[] Buffer) 
{ 
    Boolean result = false; 
    foreach (float Item in Buffer) 
    { 
     result = !(Item == (float)0); 
     if (result) break; 
    } 
    return result; 
} 

Je ne peux pas trouver un super-type « numéro » de sorte que je peux comparer « Item » dans la mise en œuvre des génériques (je ne me dérangerait pas la peine de la performance de la boxe, même si je comprends que dans .NET il n'y a pas une telle chose?):


//SOMETHING LIKE THIS? 
private Boolean AtLeastOneBufferItemIsNonZero<T>(T[] Buffer) where T : NUMBERTYPE 
{ 
    Boolean result = false; 
    foreach (T Item in Buffer) 
    { 
     result = !(Item.Equals(0)); //Nope.... 
     if (result) break; 
    } 
    return result; 
} 

est le seul moyen de créer ma propre implémentation de Number et avoir une méthode compare()? Cela ressemble à une exagération, n'est-ce pas?

+0

Il existe des questions similaires. Vérifie s'ils t'aident. Quelques exemples: http://stackoverflow.com/questions/3329576/generic-constraint-to-match-numeric-types http://stackoverflow.com/questions/802024/struggling-to-come-up-with-a -generic-c-method-that-compare-different-types-de-n – Carlos

+0

Sur une note de côté, utilisez 'bool' au lieu de' Boolean'. bool est un raccourci. – GenericTypeTea

Répondre

13

LINQ rend ce assez simple à faire, en se basant sur le fait que la valeur par défaut de tout type numérique est égal à zéro, et ils ont des méthodes d'égalité appropriées:

private bool AtLeastOneBufferItemIsNonZero<T>(T[] items) 
{ 
    T zero = default(T); 
    EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
    return items.Any(t => !comparer.Equals(t, zero)); 
} 

Maintenant, cela ne limite pas à types numériques, mais il évite la répétition. Vous pouvez aller plus loin, en généralisant à IEnumerable<T> et d'en faire une méthode d'extension:

public static class Extensions 
{ 
    public static bool ContainsNonDefaultValue<T>(this IEnumerable<T> source) 
    { 
     if (source == null) 
     { 
      throw new ArgumentNullException("source"); 
     } 
     T zero = default(T); 
     EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
     return items.Any(t => !comparer.Equals(t, zero)); 
    } 
} 

Vous pourrait limiter ce à des types de valeur en changeant la contrainte

where T : struct 

mais ce serait un IMO peu utile. Avec le changement à utiliser EqualityComparer<T>.Default, vous pouvez également utiliser la méthode pour vérifier si n'importe quelle valeur dans une séquence de type de référence est non nulle.

EDIT: Comme une note de côté, une autre façon de voir les choses est d'inverser la condition:

return !items.All(t => comparer.Equals(t, zero)); 

Cela dépend si vous êtes plus heureux avec le concept de « l'un d'eux est non nul » ou "ils ne sont pas tous zéro" :)

+0

Mais cela renvoie une valeur indiquant si au moins un élément * est * zéro? –

+0

@Fredrik: Doh, yes - correction ... –

+0

Mais ne devrait-il pas s'appeler alors 'AtLeastOneBufferItemIsZero'? –

1
private Boolean AtLeastOneBufferItemIsNonZero<T>(T[] Buffer) 
{ 
    Boolean result = false; 
    foreach (T Item in Buffer) 
    { 
     result = !Item.Equals(default(T)); //Yep!!! 
     if (result) break; 
    } 
    return result; 
} 

PS. Utiliser Linq