了解代表和任务

时间:2015-07-30 09:34:49

标签: c# .net c#-4.0 delegates

.on('keyup', function(){}).

我对该计划有几个问题:

  1. public static Task<TResult> ForEachParallel<TItem, TSubResult, TResult, TParam>(this IEnumerable items, Func<TItem, TParam, TSubResult> map, Func<TSubResult[], TResult> reduce, TParam param) { if (items == null) { throw new ArgumentNullException("items"); } if (map == null) { throw new ArgumentNullException("map"); } if (reduce == null) { throw new ArgumentNullException("reduce"); } return Task<TResult>.Factory.StartNew(() => { List<Task<TSubResult>> tasks = new List<Task<TSubResult>>(); foreach (TItem item in items) { Task<TSubResult> t = Task<TSubResult>.Factory.StartNew(item2 => { var mparam = (Tuple<TItem, TParam>)item2; return map(mparam.Item1, mparam.Item2); }, new Tuple<TItem, TParam>(item, param), TaskCreationOptions.None | TaskCreationOptions.AttachedToParent); tasks.Add(t); } List<TSubResult> results = new List<TSubResult>(); foreach (Task<TSubResult> task in tasks) { results.Add(task.Result); } return reduce(results.ToArray()); }); } static void Main(string[] args) { var a = Generate().ForEachParallel<int, int, int, int>( (element, param) => { var result = element * param; Console.WriteLine("Map: {0}, {1}", result, Task.CurrentId); Thread.Sleep(new Random(DateTime.Now.Millisecond).Next(500)); return result; }, (subresult) => { var sum = 0; foreach (var item in subresult) { sum += item; } Console.WriteLine("Reduce: {0}", sum); return sum; }, 5); Console.WriteLine(a.Result); } } static IEnumerable Generate() { for (int i = 0; i < 100; i++) { yield return i; } } 中,为什么作者没有填充4个值 (即元素,param,subresult)?
  2. main()中,元素和参数值是什么?
  3. main()中,ForEachParallel()的作用是什么?
  4. new Tuple<TItem, TParam>(item, param)ForEachParallel()中,什么是item2?作者是否称为元组 功能?

2 个答案:

答案 0 :(得分:4)

用一个简单的例子来解释这个问题最容易。

此代码:

private static string UppercaseString(string inputString)
{
    return inputString.ToUpper();
}

public static void Main()
{
    var result = UppercaseString("hello");
}

与:

完全相同
private static string UppercaseString(string inputString)
{
    return inputString.ToUpper();
}

public static void Main()
{
    Func<string, string> convert = UppercaseString;
    var result = convert("hello");
}

完全相同:

public static void Main()
{
    Func<string, string> convert = inputString => inputString.ToUpper();
    var result = convert("hello");
}

第一个例子是传统的做事方式。

第二个示例使用Func<string, string>创建指向方法(委托)的指针。

第三个例子使用lambda表达式。

在所有情况下,inputString是方法的参数。调用方法时,inputString的值设置为"hello"

示例代码中的elementparamsubresultitem2也是如此。它们都是代表的参数。无论是什么叫这些代表都有责任提出论据。

什么可能使您的代码更难理解,代理在其他方法中用作参数。例如:

private static string Hello(Func<string, string> func)
{
    return func("hello");
}

public static void Main()
{
    Func<string, string> convert = inputString => inputString.ToUpper();
    var result = Hello(convert);
}

另请参阅有关此主题的MSDN文档:https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx

答案 1 :(得分:3)

在深入研究这段代码是如何工作之前,有一些C#语言理论非常有用。我会在每个答案附近指出一个链接。

a).b)。在调用lambda表达式时,您希望填充的元素将具有值。你在main中看到的是lambda表达式,它们在声明时被调用但在被使用时不被调用。 第一个lambda将在return map(mparam.Item1, mparam.Item2);行上调用 将在return reduce(results.ToArray());行上调用第二个lambda 这个lambda表达式的起始位置可以是here

c)。当调用StartNew方法时,您可以选择使用不同的方法集(method overloading)来调用它。所以这里调用这个特定的方法签名:

public Task StartNew(Action<Object> action,
                     Object state,
                     TaskCreationOptions creationOptions)

这意味着此方法(状态)的第二个参数将是上一个操作的输入参数。

d)。因此新创建的Tuple对象将传递给lambda表达式:

item2 =>
{
    var mparam = (Tuple<TItem, TParam>)item2;
    return map(mparam.Item1, mparam.Item2);
}, 

基本上Action<object>委托表示一个方法,它接受Object类型的参数作为输入,但是你需要一个元组来访问它的项目(Item1和Item2)。这一行var mparam = (Tuple<TItem, TParam>)item2进行了从对象到元组的显式转换。

要找出未通过第4个参数的原因,您需要了解Method Extensions。实际上,第一个参数未传递,因为该方法是使用IEnumerable类型的对象调用的。这个方法扩展了IEnumerable类,而没有触及原始类,所以说“我希望这个方法扩展IEnumerable并将其用于每个IEnumerable对象”的方式&#39;是通过将第一个参数设置为IEnumerable。编译器将确保它将列表作为第一个参数发送,因此在扩展方法中您可以使用它。