哼哼, LINQ!

    习惯了用LINQ的人一定用的很爽, 整天LINQ来LINQ去的, LINQ确实是很好的东西, 简洁, 方便, 最重要的是统一了数据的查询方式, 使得程序员不必关心数据的出处(绝对不关心数据的出处是不可能的, 但至少统一了查询方式, 统一了"项目接口"), 这一点对软件工程很有意义.

    不过...........它是如何实现的呢?...................

    恩, 又是语法糖, 不这回是个超级大语法糖, 外带一些类库糖.

    如果把整个LINQ比作一个人,那我们先来写一个麻雀:

    //定义委托类型。
    public delegate T TheFun<T>();

    
//定义一个接口。
    public interface IHaveCount
    {
        
int MyCount1 { getset; }
        
int MyCount2 { getset; }
    }

    
//这是类库糖
    public static class HaveCountOperations
    {
        
//使用扩展方法这个语法糖。
        public static IHaveCount AddCount2ToCount1(this IHaveCount haveCount, TheFun<bool> ifDoOrNot)
        {
            
//执行委托,用来判断是否执行。
            if (ifDoOrNot.Invoke())
            {
                haveCount.MyCount1 
+= haveCount.MyCount2;
            }
            
return haveCount;
        }
    }

    
//定义一个类
    public class A : IHaveCount
    {
        
public string Name;

        
#region IHaveCount Members
        
public int MyCount1 { getset; }
        
public int MyCount2 { getset; }
        
#endregion
    }


    然后调用它:

            A a = new A { MyCount1 = 100, MyCount2 = 2 };
            a.AddCount2ToCount1(() 
=> true).AddCount2ToCount1(() => true).AddCount2ToCount1(() => false);

            Console.WriteLine(a.MyCount1.ToString());

    结果为104。

    
    我们回过头来看一下,不难发现在这个麻雀结构中最关键的就是类库糖中针对接口IHaveCount的扩展方法,麻雀虽小,但很能反映问题。LINQ中,最本质的也是这样一种设计思路。伟大的LINQ设计师当初就要面对这样一种场景:如何针对不同的载体类型,统一数据集的查询方式?

    绝不可能去重写所有的载体类型比如List、Array,但这些集合类型都实现了同样的一个接口:IEnumerable<T>,也就是说都是可以使用迭代器查看数据集中的每一个数据的,只要能把查询条件以某种方式传到foreach结构中,然后再返回符合条件的同样继承IEnumerable<T>的集合不就可以设计出类似sql的查询语言?查询条件可以使用委托,下一个问题是如何返回集合,当然可以新new一个,不过聪明的LINQ设计师却使用了yield return,呵,这样一来,不仅减少了代码量,还顺便实现了延迟加载的特性。这样一来,核心设计便没有问题了,可是使用起来却比较难看,于是有了扩展方法,让类库糖调用起来像实例方法一样方便,于是又产生了匿名委托,匿名方法等等等等,可以说C# 3.0绝大部分新特性都被用在了LINQ上。再结合泛型方法,泛型委托,LINQ看起来竟显得如此漂亮。

     如果把整个LINQ比作一个人,那我们最后再来写一条狗:(编译完了强烈建议大家用Reflector反编译仔细研究研究)

    public static class LINQDogOperations
    {
        
public static IEnumerable<TResult> LittleDogSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            
foreach (TSource ts in source)
            {
                
yield return selector(ts);
            }
        }

        
public static IEnumerable<TSource> LittleDogWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            
foreach (TSource ts in source)
            {
                
if (predicate(ts))
                {
                    
yield return ts;
                }
            }
        }


随便调用试试:

    class Program
    {
        
static void Main(string[] args)
        {
            List
<TestClass> test = new List<TestClass>();

            
for (int i = 0; i < 1000; i++)
            {
                test.Add(
new TestClass { ID = i, Password = i.ToString() });
            }

            var v1 
= test.LittleDogSelect((i) => new { i.ID, i.Password }).LittleDogWhere((c) => c.ID > 500);

            Console.WriteLine(v1.Count().ToString());
        }
    }


    
public class TestClass
    {
        
public int ID;
        
public string Password;
        
public int State;
    }

    呵呵,当一切语法糖条件具备,看吧,就那几行代码,感谢万能的编译器。感谢聪明的设计师。

posted @ 2008-06-18 19:41  王弈博  阅读(310)  评论(3编辑  收藏  举报