2013-09-23 5 views
6

Мне нужно написать что-то, что я называю агрегирующим контейнером, в котором хранятся агрегаты, которые по существу являются действиями, которые принимают коллекцию объектов и выводят один объект в результате. Примерами агрегаций были бы: Арифметическое среднее, медианное множество чисел, гармоническое среднее и т. Д. Вот пример кода.Агрегация и как проверить, можем ли мы суммировать объекты

var arithmeticMean = new Aggregation 
     { 
      Descriptor = new AggregationDescriptor { Name = "Arithmetic Mean" }, 
      Action = (IEnumerable arg) => 
      { 
       double count = 0; 
       double sum = 0; 

       foreach (var item in arg) 
       { 
        sum += (double)item; 
        count++; 
       } 

       return sum/count; 
      } 
     }; 

Это моя проблема с кодом. Я предположил, что объекты были просто двойными и, следовательно, сделали преобразование. Что делать, если они не удваиваются? Как я могу убедиться, что мне разрешено суммировать два объекта? Есть ли какой-то интерфейс для этого в стандартных сборках .Net? Мне нужно что-то вроде ISummable ... Или мне нужно реализовать его самостоятельно (тогда мне придется обернуть все примитивные типы, такие как double, int и т. Д., Чтобы поддерживать его).

Любой совет, касающийся дизайна такой функциональности, будет полезен.

+1

Проблема не что вы необходимо определить, является ли коллекция «суммируемой». Все числовые значения по существу суммируются. Вместо этого вы должны задать вопрос: «Является ли' arg' набором чисел? ». Вы можете попробовать либо предоставить строго типизированные вариации «Действие» для разных числовых типов, либо время выполнения на «arg». – Jon

+0

Джон, спасибо за ответ. Я знаю, примеры, которые я дал, являются числовыми ... Но я бы очень хотел написать что-то более общее и полезное. Я бы не хотел писать кучу запусков, но я предлагаю, что здесь будет работать набор действий с различными типами аргументов ... –

+3

Посмотрите на Enumerable methods - у него есть набор общих методов, параметризованных с каждым типом поддерживает: 'Sum , Sum , Sum , Sum >' и т. д. Это единственный способ сделать параметр типа «суммируемым» –

ответ

3

Посмотрите на Enumerable методы класса - это совокупность методов, параметризованных с каждым типом он поддерживает:

int Sum(this IEnumerable<int> source) 
double Sum(this IEnumerable<double> source) 
decimal Sum(this IEnumerable<decimal> source) 
long Sum(this IEnumerable<long> source) 
int? Sum(this IEnumerable<int?> source) 
// etc 

Это единственный способ сделать метод аргумент, чтобы быть 'суммируем.

К сожалению, вы не можете создать общий метод с общим type parameter constraint, который позволит использовать только типы с + перегрузкой оператора. В .NET нет ограничений для операторов, также операторы не могут быть частью некоторого интерфейса (поэтому они являются статическими). Таким образом, вы не можете использовать операторы с переменными общего типа.

Кроме того, если вы будете смотреть на .NET определения примитивных типов, вы не найдете каких-либо интерфейс, который может помочь вам здесь - только сравнения, форматирования и преобразования реализуются:

public struct Int32 : IComparable, IFormattable, IConvertible, 
         IComparable<int>, IEquatable<int> 
0

Вы можете изменить свой Action свойство в классе, как:

public Func<IEnumerable<double>, double> Action { get; set; } 

Так что это будет только кроме IEnumerable<double> и возвращает double результат.

+0

Я на самом деле пытаюсь отвлечься от типа коллекции, чтобы я мог суммировать все, что можно как-то суммировать. –

+1

@ george.zakaryan Затем вы можете создать 2 перегрузки для Action: 'Action (IEnumerable )' и 'Action (IEnumerable )', где ISummable должен быть вашим интерфейсом. Двойной неявно отбрасывается на любой другой числовой тип. – selfnamed

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