2010-09-23 10 views
5

Ich bin ziemlich neu in C# aus Java, und ich frage mich, ob es ein einfacher Weg, Code Wiederholung die primitive Typen wie dies zu vermeiden:C# Generika zur Vermeidung von Code-Wiederholungen?


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; 
} 

ich keinen „Nummer“ Supertyp so finden dass ich vergleichen kann „Item“ in einer Generika-Implementierung (ich würde nicht die Leistungseinbuße des Boxens dagegen, obwohl ich verstehe, dass so etwas gibt es nicht in .NET?):


//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; 
} 

ist der einzige Weg zu Erstelle meine eigene Zahlenimplementierung und eine compare() Methode? Das klingt nach Overkill, oder?

+0

Es gibt einige ähnliche Fragen. Überprüfen Sie, ob sie Ihnen helfen. Einige Beispiele: 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-das-vergleicht-verschiedene-type-of-n – Carlos

+0

Nebenbei bemerkt, verwenden Sie 'bool' anstelle von' Boolean'. Bool ist eine Abkürzung. – GenericTypeTea

Antwort

13

LINQ macht dies ziemlich einfach zu tun, auf der Tatsache, indem sie sich, dass der Standardwert eines numerischen Typ Null ist, und sie haben entsprechende Gleichheit Methoden:

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

Jetzt geht das beschränken sie nicht auf numerische Typen, vermeidet jedoch Wiederholungen. Sie können weiter gehen, indem sie IEnumerable<T> verallgemeinern und eine Erweiterungsmethode zu machen:

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)); 
    } 
} 

Sie könnte dies

durch Änderung der Beschränkung auf Werttypen beschränken
where T : struct 

aber das wäre ein sein Bit sinnlos IMO. Mit der zu verwendenden Änderung EqualityComparer<T>.Default können Sie auch die Methode verwenden, um zu überprüfen, ob ein Wert in einer Referenztypsequenz nicht null ist.

EDIT: Als Randbemerkung, eine andere Art und Weise der Blick auf sie ist die Bedingung zu umkehren:

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

Es hängt davon ab, ob Sie glücklicher mit dem Konzept „einer von ihnen ist nicht Null“ oder "sie sind nicht alle null" :)

+0

Aber das gibt einen Wert zurück, der angibt, ob mindestens ein Element * Null ist? –

+0

@Fredrik: Doh, ja - Befestigung ... –

+0

Aber sollte das nicht dann 'AtLeastOneBufferItemIsZero' genannt werden? –

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. Verwenden Sie Linq