5

I am fairly new to C# coming from Java, and I'm wondering if there's a simple way to avoid code repetition involving primitive types like this:


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

I can't find a "Number" supertype so that I can compare "Item" in a generics implementation (I wouldn't mind the performance penalty of boxing, although I understand that in .NET there is no such thing?):


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

Is the only way to create my own Number implementation and having a compare() method? That sounds like overkill doesn't it?

Mastermnd
  • 172
  • 8
  • There are some similar questions. Check if they help you. Couple of examples: 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-compares-different-types-of-n – Carlos Sep 23 '10 at 19:58
  • On a side note, use `bool` instead of `Boolean`. bool is a shortcut. – djdd87 Sep 23 '10 at 20:00

2 Answers2

13

LINQ makes this pretty simple to do, by relying on the fact that the default value of any numeric type is zero, and they have appropriate equality methods:

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

Now that doesn't restrict it to numeric types, but it does avoid repetition. You can go further, by generalizing it to IEnumerable<T> and making it an extension method:

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

You could restrict this to value types by changing the constraint to

where T : struct

but that would be a bit pointless IMO. With the change to use EqualityComparer<T>.Default, you can also use the method to check whether any value in a reference type sequence is non-null.

EDIT: As a side note, another way of look at it is to reverse the condition:

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

It depends whether you're happier with the concept of "any of them is non-zero" or "they're not all zero" :)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
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. Use Linq

gandjustas
  • 1,925
  • 14
  • 12