Вопросы о функциях делегата в C #? - PullRequest
1 голос
/ 13 октября 2011

Я изучаю C # и одной из областей, которые меня интересовали, были функции делегирования.В следующем коде они используются для применения функции к каждому числу в диапазоне [start, limit [до суммирования).Это довольно простой пример для ясности.

// function passing a delegate function
public override void solveProblem() {
    int squareOfSum = (int) Math.Pow(Library.Math.sumRange(1, 101), 2);
    int sumOfSquares = Library.Math.sumRange(1, 101, new Func<double, double, double>(Math.Pow), 2);

    this.solution = (squareOfSum - sumOfSquares).ToString();
}

// function that accepts / uses delegate function
static public int sumRange(int start, int limit, Delegate operation, params object[] args) {
    int sum = 0;

    for (int current = start; current < limit; current++) {
        // add the current number in the range as an arguement
        object[] newArgs = new object[args.Length + 1];
        newArgs[0] = current;
        args.CopyTo(newArgs, 1);

        // sum the result of the operation (delegate function)
        sum += Convert.ToInt32(operation.DynamicInvoke(newArgs));
    }

    return sum;
}

У меня есть следующие конкретные вопросы:

  • Можно ли использовать динамические функции делегата (которые принимают переменнуюдлина списка параметров с неизвестными типами) но вынуждает функцию делегата возвращать определенный тип?С нединамическими функциями делегата вы устанавливаете тип возвращаемого значения, но также должны указывать количество параметров и их типов.

  • Насколько медленнее использование DynamicInvoke, чем использование нединамического делегатаfunction?

  • Каков наилучший способ обработки параметров, чем тот, который я в данный момент делаю (который принимает список других параметров и добавляет любые параметры, которые должна добавить функция, использующая делегат))?

  • Нужно ли объявлять 'new Func (Math.Pow)' для передачи в функцию power, или есть способ просто передать Math.Pow (и получитьвозвращаемый тип и параметры передаются неявно)?

Я посмотрел на документы C # и этот вопрос StackOverflow , чтобы узнать, как использовать функции делегата, я просто хочуузнать о них больше.

Спасибо!

jtfairbank

Ответы [ 2 ]

2 голосов
/ 13 октября 2011

Можно ли использовать динамические функции делегата (которые принимают переменная длина списка параметров с неизвестными типами), но принудительно функция делегата для возврата определенного типа? С нединамическим делегатом функции, которые вы устанавливаете тип возврата, но также должны установить количество параметры и их типы.

Вы не «заставляете» функцию возвращать что-либо. Функция возвращает что-то или не возвращает что-то. Функция «заставляет» вас что-то принимать :-) (или игнорировать это)

Вы можете вызвать динамический делегат через DynamicInvoke, а затем привести возвращаемое значение к тому, что, как вы знаете, возвращает ваш делегат (или вы сохраняете его как object). Я говорю «то, что, как вы знаете, возвращает ваш делегат», но реальность немного сложнее: для типов значений вы должны привести возвращаемое значение точно к типу, используемому в качестве возвращаемого значения, или вы получите InvalidCastException. Для ссылочных типов вы можете использовать интерфейс или базовый класс возвращаемого объекта (за некоторыми исключениями для типов Nullable)

Насколько медленнее использование DynamicInvoke, чем использование нединамического делегата?

Я протестировал метод void Do() (самый простой из возможных, без упаковки параметров), и разница во времени была незначительной. Скажем, 400x :-) На http://ideone.com/f34cj это между 70x и 150x.

Нужно ли объявлять 'new Func (Math.Pow)' для передачи функции power, или есть способ просто передать Math.Pow (и неявно передать тип и параметры возврата)?

Создание нового делегата Func / Action - правильный путь.


В общем, правильное решение - это не то, что вы делаете. Правильное решение - это делать, как это делает LINQ. Например:

int pow = 2;
Func<int, int> myFunc = p => (int)Math.Pow(p, pow);

var listOfNumbers = Enumerable.Range(1, 100);

var result = listOfNumbers.Sum(p => myFunc(p));

Теперь у вас есть делегат (myFunc), который берет число и возвращает квадрат этого числа (и обратите внимание, что через «замыкания» он закрывается около pow) (если вы не знаете, что такое замыкание попробуйте вставить это слово в Google с помощью функции лямбда-слов). Список чисел в виде IEnumerable<int>, и вы делаете сумму этих чисел, «преобразованную» в myFunc.

1 голос
/ 13 октября 2011

Читай на LINQ - использование IEnumerable дает гораздо более компактный код.

т.е. комбинация Enumrable.Range (http://msdn.microsoft.com/en-us/library/system.linq.enumerable.range.aspx) и Enumerable.Aggregate (http://msdn.microsoft.com/en-us/library/bb548651.aspx) - это именно то, чего вы пытаетесь достичь:

var sum = Enumerable.Range(start,limit).Aggregate((s, cur)=> s+cur);
var sumSq = Enumerable.Range(start,limit).Aggregate((s, cur)=> s+ cur * cur);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...