有关C#中委托函数的问题?

时间:2011-10-13 16:59:38

标签: c# delegates

我正在学习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比使用非动态委托功能慢多少?

  • 处理参数的最佳方法是什么(我接受其他参数的列表,并在其中添加使用委托需要添加的函数的任何参数)?

  • 我是否需要声明'new Func(Math.Pow)'来传递幂函数,或者是否有办法只传递Math.Pow(并且隐式传递返回类型和参数)

我查看了C#docs和this StackOverflow question以了解如何使用委托功能,我只想了解更多相关信息。

谢谢!

jtfairbank

2 个答案:

答案 0 :(得分:2)

  

是否可以使用动态委托函数(接受a   具有未知类型的参数的可变长度列表)但强制   委托函数返回特定类型?使用非动态委托   函数你设置一个返回类型,但也必须设置数量   参数及其类型。

你没有“强制”函数返回一些东西。该函数返回一些东西或它不返回一些东西。该功能“强迫”你接受某些东西:-)(或忽略它)

您可以通过DynamicInvoke调用动态委托,然后将返回值转换为您知道委托返回的内容(或者将其保留为object)。我说“你知道你的代理人返回了什么”但实际情况稍微复杂一些:对于价值类型,你必须将返回值精确地转换为用作返回值的类型,否则你将获得InvalidCastException。对于引用类型,您可以使用返回的对象的接口或基类(对于Nullable类型有一些例外)

  

使用DynamicInvoke比使用非动态委托函数慢多少?

我已经测试了一个void Do()方法(可能是最简单的方法,没有参数装箱),时间差是贬义的。让我们说400x :-)在http://ideone.com/f34cj,它介于70x和150x之间。

  

我是否需要声明'new Func(Math.Pow)'来传递幂函数,或者是否有办法只传递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附近关闭)(如果您不这样做)知道封闭是什么,尝试用谷歌函数把这个词放在谷歌中。作为IEnumerable<int>的数字列表,您可以按myFunc“转换”这些数字的总和。

答案 1 :(得分:1)

读取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);