首页 > 代码库 > 什么是LINQ? (上)

什么是LINQ? (上)

  什么是LINQ?LINQ(Language Integrated Query)的全称就是语言集成查询,是为了各种不同的数据源提供一个统一的接口。通过这个接口,查询各种数据源可以使用将近一致的方式和语法。根据各种不同的数据源,接口有着不同的实现。而接口的调用者,通常是各种各样的应用程序。根据数据源的不同,产生了不同的LINQ分支,如LINQ To Objects, LINQ To SQL, LINQ To XML等。下面先简单说一下LINQ涉及到的基础知识。

  一、泛型委托

   委托是方法的抽象,泛型是类型的抽象,他们两个的组合使得我们可以定义任意参数和返回值的方法。我们只要批量定义一组委托,这些委托的参数个数是不同的,返回值和参数类型全部都是泛型的,那就可以表示某一参数个数范围内的任意方法了。.Net有两种委托,一种是Func<T,TResult>,T代表参数类型,TResult是返回值类型,另一种是Action<T>,Action和Func类似,但是不包含返回值。

  二、隐式类型和匿名类型

  在声明一个隐式类型时,必须对它赋值。而且var只能用于局部变量,不能将字段、属性和方法的返回值声明为隐式类型。值得注意的是,使用var声明一个隐式类型,该变量依然能够使用该类型的方法,也就是说编译器能智能识别该局部变量。

var _linq = "LINQ";

  隐式类型最好跟匿名类型结合使用。单独使用隐式类型的声明会使得代码可读性变差。匿名类型允许我们直接创建类型的实例,而不必预先定义该类型。也就是说,没有这个类,凭空生成一个对象。

var s = new {name = "Jack"};

  三、扩展方法

  什么是扩展方法?扩展方法通过编写一个新的类给原来的类增加新的方法。有两个要求:扩展方法所在的类必须为静态类且扩展方法必须是静态方法;被扩展的类型作为扩展方法的第一个参数传递进去,并且前面加上this关键字。通常扩展方法所在的类型使用Extension作为结尾。注意别把扩展方法声明为内部类。

  

public static class StringExtension{    public static void SayHello(this string str){Debug.Log ("hello!");}}

  现在可以使用这个扩展方法了。

string jack = "jack";jack.SayHello ();

  四、匿名方法和Lambda表达式

  就像隐式类型声明和匿名对象有较好的契合一样,匿名方法和Lambda表达式也有很深的关系。匿名方法有什么用?匿名方法允许我们将代码块传递为委托参数,并且减少了实例化委托所需的编码系统开销。例如下面的例子,我们不必实际写一个方法,再让委托等于该方法了。

public delegate void myDelegate();myDelegate md;md = delegate() {Debug.Log ("匿名方法");};

  匿名方法使用delegate关键字声明,后面跟着方法的参数列表,然后在花括号中编写方法的内容。假如不需要用到方法的参数时,可以将参数列表省略。考虑到这一点,我们可以将匿名方法转换为具有各种参数的委托。但是这个好像没有多大意义,因为你都把参数列表忽视了呀。

public delegate void anotherDelegate(string name);anotherDelegate ad;ad = delegate {Debug.Log("一个参数的匿名方法");};  

  此外,我们还可以直接在方法里面访问在方法外部声明的变量。

  什么是Lambda表达式?Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数。Lambda表达式省略了delegate关键字,也省略了参数类型。Lambda运算符=>左边是参数,右边是方法体。假如方法体不止一行,就要加上花括号。如果没有花括号呢,默认就把方法体的执行结果作为返回值,假如有了花括号,必须使用return关键字来明确返回执行结果。

ad += (x)=>Debug.Log(x);

  详细的关于Lambda表达式:http://msdn.microsoft.com/zh-cn/library/bb397687.aspx

   五、集合

  什么是集合?集合有以下特性:

  1、可以通过索引或键来访问集合的成员,如collection[index]或collection[key]。

  2、可以使用for、foreach进行遍历

  3、提供一些方法,用于获得集合成员数量、添加和移除成员,如Count,Length,Add(),Remove(),Clear()等。

  现在我们自己创建一个Product类。

using UnityEngine;using System.Collections;public class Product {    public int id { get; set;}    public string code { get; set;}    public string _name { get; set;}    public static ProductCollection GetSampleCollection(){        ProductCollection collection = new ProductCollection (            new Product[]{new Product(){id =1, code = "1001", _name = "wine"},            new Product(){id =2, code = "1002", _name = "wine"},            new Product(){id =3, code = "1003", _name = "wine"},            new Product(){id =4, code = "1004", _name = "wine"},            new Product(){id =5, code = "1005", _name = "wine"},            new Product(){id =6, code = "1006", _name = "wine"},            new Product(){id =7, code = "1007", _name = "wine"},            new Product(){id =8, code = "1008", _name = "wine"}}            );        return collection;    }    public override string ToString ()    {        return string.Format ("[Product: id={0}, code={1}, _name={2}]", id.ToString(), code, _name);    }}

  接下来创建一个集合类ProductCollection。

using UnityEngine;using System.Collections;using System;public class ProductCollection{    private Hashtable hashtable;    public ICollection Keys{ get{ return hashtable.Keys;}}    public ProductCollection(params Product[] items){        hashtable = new Hashtable ();        foreach (Product item in items) {            this.Add(item);        }    }    public void Add(Product item){        hashtable.Add (item.code, item);    }    public int Count {get { return hashtable.Keys.Count;}}    public string GetKey(int index){        if(index<0 || index>hashtable.Keys.Count)            throw new Exception("index is out of range");        string selected = "";        int i = 0;        foreach (string item in hashtable.Keys) {            if(i == index){                selected = item;                break;            }            i++;        }        return selected;    }        public Product this[int index]{        get{            string key = GetKey(index);            return hashtable[key] as Product;        }    }}

  下面测试一下这两个类。

using UnityEngine;using System.Collections;public class _Test : MonoBehaviour {    // Use this for initialization    void Start () {        ProductCollection collection = Product.GetSampleCollection ();        Debug.Log (collection.Count);        Debug.Log (string.Format("第{0}个下标的键是{1}","6",collection.GetKey(6)));        for (int i = 0; i < collection.Count; i++) {            string line = collection[i].ToString();            Debug.Log(line);                }    }}

  可以看到ProductCollection类已经可以使用[]操作符来访问对象。如果想让ProductCollection类支持foreach循环,需要实现IEnumerable<T>接口。

public interface IEnumberable<out T> :IEnumerable{    IEnumerator<T> GetEnumerator();}

  IEnumerable<T>接口实现了IEnumerable接口。

public interface IEnumerable{    IEnumerator GetEnumerator();}

  我们通过编写一个类来实现这两个接口。这个类应该实现IEnumerator<T>接口。而IEnumerator<T>接口又实现了IEnumerator和IDisposable接口。

public interface IEnumerator<out T> :IDisposable, IEnumerator{  T Current { get;}  }public interface IEnumerator{  object Current {get;}  bool MoveNext();  void Reset();      }public interface IDisposable{  void Dispose();  }

  下面往刚才的类里添加几行代码。这只是类的前面部分,重复的省略了。

public class ProductCollection : IEnumerable<Product>{    public class ProductEnumerator :IEnumerator<Product>{        private ProductCollection collection;        private int index;        public ProductEnumerator (ProductCollection col){            this.collection = col;            index = -1;        }        public Product Current{get { return collection[index];}}        object IEnumerator.Current{get { return collection[index];}}        public bool MoveNext(){            index ++;            if (index >= collection.Count)                                return false;                        else                                return true;        }        public void Reset(){ index = -1;}        public void Dispose(){}    }    public IEnumerator<Product> GetEnumerator(){        return new ProductEnumerator (this);    }    IEnumerator IEnumerable.GetEnumerator(){        return new ProductEnumerator (this);    }
  //省略重复代码
}

  现在可以使用迭代器遍历我们的ProductCollection了。

//第一种遍历方式IEnumerator<Product> p = collection.GetEnumerator ();    while (p.MoveNext()) {        string line = p.Current.ToString();        Debug.Log(line);}//第二种遍历方式foreach (Product p in collection) {    string line = p.ToString();    Debug.Log(line);}

   所有实现了IEnumerable<T>的对象,都可以进行遍历,描述这类对象的术语叫做序列。序列仅仅关心是否可以遍历。

什么是LINQ? (上)