2010-09-23 4 views
5

Я довольно новыми для C# наступающем от Java, и мне интересно, если есть простой способ избежать повторения кода с участием примитивных типов, как это:C# Generics, чтобы избежать повторения кода?


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

Я не могу найти «номер» супертип так что я могу сравнить «Элемент» в реализации дженериков (я бы не против ухудшая производительность бокса, хотя я понимаю, что в .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; 
} 

это единственный способ создать мою собственную реализацию Number и иметь метод compare()? Это звучит как перебор, не так ли?

+0

Есть несколько аналогичных вопросов. Проверьте, помогают ли они вам. Пара примеров: 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-comparees-different-types-of-n – Carlos

+0

На боковой ноте используйте 'bool' вместо' Boolean'. bool - это ярлык. – GenericTypeTea

ответ

13

LINQ делает это довольно просто сделать, опираясь на тот факт, что значение по умолчанию любого числового типа равен нулю, и они имеют соответствующие методы равенства:

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

Теперь, не ограничивает его числовые типы, но это позволяет избежать повторения. Вы можете пойти дальше, обобщив его IEnumerable<T> и сделать его метод расширения:

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

Вы могли ограничить это типы значений, изменив ограничение на

where T : struct 

, но это было бы бит бессмысленной ИМО. С заменой на использование EqualityComparer<T>.Default вы можете использовать также, чтобы проверить, не имеет ли значение в последовательности ссылочного типа значение null.

EDIT: В качестве примечания, еще один способ взглянуть на это должен обратить условие:

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

Это зависит от того, вы счастливее с понятием «ни один из них не равен нулю» или «они не все равны нулю»)

+0

Но это возвращает значение, указывающее, является ли хотя бы один элемент * равным нулю? –

+0

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

+0

Но разве это не должно быть названо '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. Использование Linq

Смежные вопросы