从 Comparison/Converter 到Func 的进化

本篇文章给大家介绍两个在.net2.0 中就已经出现的, 很"老"的委托方式.

通常情况下, 我们在Array 和 List<T> 类中使用这些功能. 明白用法和作用可以帮助你自如的使用它们.

但是你也可以使用和它们作用相同的Func 家族的形式 -- 在.NET 2.0 之后引入的新功能.

通过了解这些基本信息可以帮助我们看到一部分.net 进化的过程. 我称这种内容为"历史".

 

只是抛砖引玉, 希望大家多多交流

Comparison<T>

它的出现是为了对Array 和 List<T> 执行type-safe 排序.

注意, Linq函数的 OrderBy(), ThenBy() 是不支持comparison<T>委托的.

看下面的实例:

using System;
using System.Collections.Generic;
using System.Linq;


public class Hero
{
public string Name { get; set; }
public int Age { get; set; }
public double Power { get; set; }
}

class Program
{
static void Main(string[] args)
{
var heroes = new List<Hero>
{
new Hero {Name = "Goku", Age = 60, Power = 1000.00},
new Hero {Name = "Vegeta", Age = 65, Power = 800.00},
new Hero {Name = "Ikki", Age = 22,Power = 345.30},
new Hero {Name = "Dr. Slump", Age = 40, Power = 1.23},
};

Console.WriteLine("***** sort by age ****");
heroes.Sort((lhs, rhs) => Comparer<int>.Default.Compare(lhs.Age, rhs.Age));
Print(heroes);
Console.WriteLine("***** sort by name ****");
heroes.Sort((lhs, rhs) => string.Compare(lhs.Name, rhs.Name));
Print(heroes);
Console.WriteLine("***** sort by power ****");
heroes.Sort((lhs, rhs) => Comparer<double>.Default.Compare(rhs.Power, lhs.Power));
Print(heroes);

Console.Read();
}

private static void Print(IEnumerable<Hero> heroes)
{
foreach (var hero in heroes)
{
Console.WriteLine(hero.Name + "(" + hero.Age + ")");
}
}
 
很容易理解上面几种排序的方法. 那么使用新的Func时, 实现如下:

 

Console.WriteLine("***** sort by name(Func) ****");
var heroesOrderByName = heroes.OrderBy(t => t.Name);
Print(heroesOrderByName);

在这种情况下Comparison<T> 使用较少的原因, 就是相对代码工作量大, 实现复杂一些.

Converter<TInput, TOutput>

Converter的使用是对某种类型的列表或者数组进行操作, 将其转化为另外一个类型的列表或者数组.

继续使用上面的代码, 插入:

Console.WriteLine("***** TestFunc ****");
TestFunc(heroes);

Console.WriteLine("***** TestConverter ****");
TestConverter(heroes);

Console.WriteLine("***** TestLinqSelect ****");
TestLinqSelect(heroes);

private static void TestFunc(List<Hero> heroes)
{
Func<Hero, string> selector = p => p.Name;

IEnumerable<string> names = heroes.Select(selector);

print(names);
}

private static void TestLinqSelect(List<Hero> heroes)
{
var names = heroes.Select(p => p.Name);

print(names);
}

private static void TestConverter(List<Hero> heroes)
{
var names = heroes.ConvertAll(p => p.Name);

print(names);
}


private static void print(IEnumerable<string> names)
{
foreach (string name in names)
Console.WriteLine(name);
}
其实上面 TestLinqSelect 和 TestFunc 是同一码事, 我只是给大家提供不同的代码方案而已. 一般, 我们不会使用TestFunc 这种形式.
注意, 用 Linq 的Select 和其他一些Linq的函数一样, 是推迟执行, 这意味着, 很多时候, 它们将不执行转换, 直到数值被使用.
 
这事实上是双刃剑, 有时候它可以获取更好的效率, 但是如果你马上就想要结果就会导致额外的后台工作开销 -- 支持延迟执行的功能本身需要使用到yield return /yield break 来维持当前状态的信息迭代器.

小结

本质上来讲, Comparison/Converter 和与之相对应的Func没有太多区别, 但是为什么.net 让它们同时存在, 或者换句话讲在有了实现方案后, 为什么要"多余"引入后者?

这是因为之后被引入的委托Func<>是一个多功能兵种, 但是在执行具体任务的时候效果稍有区别.

在新项目中, 我们也更倾向于使用新的方法.

参考文章:C#/.NET Little Wonders: The Predicate, Comparison, and Converter Generic Delegates

本文来自于喜乐的ASP.NET(Alex Song) 转贴请注明出处

posted @ 2011-11-30 05:32  拥有的都是恩典  阅读(1874)  评论(2编辑  收藏  举报