久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linq to “everything you want” 深入淺出(一) 實(shí)現(xiàn)IQueryable的基類

 nikybook 2015-07-18

Linq to “everything you want” 深入淺出(一) 實(shí)現(xiàn)IQueryable的基類

  為了節(jié)省大家的時(shí)間,,希望先了解Expression Tree然后再看本系列的文章,關(guān)于這些方面的介紹,,建議查看TerryLee的打造自己的LINQ Provider:Expression Tree揭秘

  前言:之所以要發(fā)出這個(gè)系列,,主要是之前在發(fā)出的.NET 業(yè)務(wù)框架開發(fā)實(shí)戰(zhàn)之八 業(yè)務(wù)層Mapping的選擇策略 一文中,,提到了查詢對(duì)象的實(shí)現(xiàn)。在文章發(fā)出之后,,園子里的朋友給出很多非常不錯(cuò)評(píng)論反饋,,其中園友mywork提出了非常好的建議:提議用Expression Tree來(lái)實(shí)現(xiàn)。同時(shí)Harold Shen也提出了這個(gè)建議,。在博客園里 Linq Provider的文章很多,,那就當(dāng)給博客園里面的Linq主題多添加一點(diǎn)資料吧,分享一下,,同時(shí)也為.NET業(yè)務(wù)框架實(shí)戰(zhàn)系列中條件對(duì)象(查詢對(duì)象只是條件對(duì)象的一種)的實(shí)現(xiàn)做鋪路,。 J.

  現(xiàn)在有很多的linq to XXX(Linq to sql,Linq to javascript等),所以文章的標(biāo)題意思大家就已經(jīng)明白了。

   本篇議題如下:

  1. 條件對(duì)象怎樣實(shí)現(xiàn)

  2. IQueryable介紹

  3. IQueryProvider介紹

  4. IQueryable的基類實(shí)現(xiàn)

 

1.  條件對(duì)象怎樣實(shí)現(xiàn)

 

開始的時(shí)候,,條件對(duì)象的實(shí)現(xiàn)如下:

 

ICriteria condition=CriteriaFactory.Create(typeof(ProductBL).Where("ProductName", Operation.Equal,"book");

  

采用這種方式固然靈活,,但是最大的問(wèn)題就是Where后面的條件:ProductName是基于字符串的,缺少編譯器的智能感應(yīng),,而且如果ProductBL的ProductName改變?yōu)榱?/span>Name,,,有些地方可能仍然采用的ProductName,且這樣的錯(cuò)誤很難發(fā)現(xiàn),,只有在運(yùn)行時(shí)才知道,,再者Where條件的構(gòu)造也顯得有點(diǎn)復(fù)雜(和現(xiàn)在的linq相比)。如果換成如下的方式,,可能就更好一些: 

 

ICriteria<T> condition=CriteriaFactory.Create<T>(Expression<Func<T,bool>> func);

    使用時(shí)

ICriteria<ProductBL> condition=CriteriaFactory.Create<ProductBL>(o => o.ProductName == "book");

  

惟一很問(wèn)題就是解析Expression樹,。

而且上面的代碼是在UI代碼中被調(diào)用,然后,,ICriteria 對(duì)象最后會(huì)被傳到BLL,,最后傳到DAL,解析為SQL語(yǔ)句進(jìn)行執(zhí)行,。 

趁實(shí)現(xiàn)條件對(duì)象的機(jī)會(huì),,把IQueryable Provider具體的講述一下,一舉兩得。  

 

2. IQueryable介紹 

我們從IQueryable接口入手,,首先來(lái)看看接口的定義: 

復(fù)制代碼
public interface IQueryable : IEnumerable
 {
      Type ElementType { get; }
      Expression Expression { get; }
      IQueryProvider Provider { get; }

 }

復(fù)制代碼

  

           接口中定義了三個(gè)只讀的屬性,,簡(jiǎn)單的理解:ElementType表示查詢返回對(duì)象的類型;Expression就是查詢條件集合(Expression可以組成一棵樹),,Provider就是用來(lái)解析Expression的對(duì)象,。下面的接口是上面接口的泛型版:

 

public interface IQueryable<T> : IEnumerable<T>, IQueryable, IEnumerable
{

}

 

            IQueryable對(duì)象的本質(zhì)就是一個(gè)表達(dá)式,這個(gè)表達(dá)式體現(xiàn)了在linq查詢時(shí)方法的調(diào)用,。

怎么講:首先在這里不得不提及System.Linq.Queryable類,,這個(gè)類在實(shí)現(xiàn)Linq的查詢中起了很大的作用,代碼如下:

  

代碼

       

  這個(gè)類的方法很多,而且這個(gè)類是專門用來(lái)對(duì)IQueryable添加擴(kuò)展方法的,。其中,,當(dāng)我們使用Queryable.Where的方法時(shí)在IQueryable對(duì)象上進(jìn)行過(guò)濾時(shí),Where方法在IQueryableExpression的表達(dá)式屬性的頂層添加了一個(gè)表示方法調(diào)用的表達(dá)式節(jié)點(diǎn)(也是Expression類型的),,這個(gè)節(jié)點(diǎn)表示你已經(jīng)調(diào)用了Queryable.Where方法,。QueryableIQueryable添加表達(dá)式樹的節(jié)點(diǎn)。

  所以說(shuō)IQueryable對(duì)象的本質(zhì)就是一個(gè)體現(xiàn)了其上的查詢方法調(diào)用的一個(gè)記錄樹,。這樣當(dāng)這個(gè)IQueryable在被IQueryProvider解析的時(shí)候,,IQueryProvider就一步步的解析這顆記錄樹。

3.  IQueryProvider介紹

正如我們上面介紹的,,IQueryProvider才是真正用來(lái)解析Linq查詢的:

 

復(fù)制代碼
public interface IQueryProvider
 {
        IQueryable CreateQuery(Expression expression);

        IQueryable<TElement> CreateQuery<TElement>(Expression expression);

        object Execute(Expression expression);

        TResult Execute<TResult>(Expression expression);


復(fù)制代碼

   

  其實(shí)這個(gè)接口說(shuō)到底就只有兩個(gè)方法,,CreateQuery,Execute.

  CreateQuery方法一看就知道是干什么:這個(gè)方法就讓Provider基于傳入的Expression創(chuàng)建一個(gè)新的IQueryable實(shí)例,隨后Provider就處理這個(gè)IQueryable實(shí)例的Expression.

  Execute就是真正的來(lái)解析表達(dá)式(expression)的,。實(shí)際就是遍歷Expression,,然后一個(gè)個(gè)的處理,。

  下面我們就來(lái)看一個(gè)例子:

復(fù)制代碼
public class Query<T> : IQueryable<T>, IQueryable, IEnumerable<T>, IEnumerable, IOrderedQueryable<T>, IOrderedQueryable {

        QueryProvider provider;
        Expression expression;

        public Query(QueryProvider provider) {

            if (provider == null) {

                throw new ArgumentNullException("provider");

            }

            this.provider = provider;
            this.expression = Expression.Constant(this);

        } 

        public Query(QueryProvider provider, Expression expression) {

            if (provider == null) {

                throw new ArgumentNullException("provider");
            }

            if (expression == null) {
                throw new ArgumentNullException("expression");
            }

            if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type)) {
                throw new ArgumentOutOfRangeException("expression");
            }

            this.provider = provider; 
            this.expression = expression;
        } 

        Expression IQueryable.Expression {
            get { return this.expression; }
        } 

        Type IQueryable.ElementType {
            get { return typeof(T); }
        } 

        IQueryProvider IQueryable.Provider {
            get { return this.provider; }
        } 

        public IEnumerator<T> GetEnumerator() {
            return ((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
        } 

        IEnumerator IEnumerable.GetEnumerator() {
            return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator();
        } 

        public override string ToString() {
            return this.provider.GetQueryText(this.expression);
        }
    }

復(fù)制代碼

 

 

  上面的代碼看起來(lái)有點(diǎn)多,,有點(diǎn)嚇人,其實(shí)上面的代碼就只是簡(jiǎn)單的實(shí)現(xiàn)了那些接口,。而且我們之前也說(shuō)過(guò):實(shí)現(xiàn)IQueryable的對(duì)象基本不做什么事情,,而是把事情都交給Provider來(lái)處理,而Provider處理過(guò)程也是很簡(jiǎn)單的:遍歷Expression,調(diào)用Execute方法解析:

      

復(fù)制代碼
  public IEnumerator<T> GetEnumerator() {
            return ((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator();
        }

復(fù)制代碼

  

       所以在實(shí)現(xiàn)的過(guò)程中,,最重要的方法就是ProviderExecute,。下面看看一個(gè)IQueryProvider實(shí)現(xiàn)的例子: 

復(fù)制代碼
public abstract class QueryProvider : IQueryProvider {
        protected QueryProvider() {
        }
        // 正如之前所說(shuō)的:CreateQuery方法就是根據(jù)傳入的expression,創(chuàng)建一個(gè)新的Query對(duì)象,。
        IQueryable<S> IQueryProvider.CreateQuery<S>(Expression expression) {
            return new Query<S>(this, expression);
        } 

        IQueryable IQueryProvider.CreateQuery(Expression expression) {
            Type elementType = TypeSystem.GetElementType(expression.Type);
            try {
                return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression });
            }
            catch (TargetInvocationException tie) {
                throw tie.InnerException;
            }
        } 

        S IQueryProvider.Execute<S>(Expression expression) {
            return (S)this.Execute(expression);
        } 

        object IQueryProvider.Execute(Expression expression) {
            return this.Execute(expression);
        } 

        public abstract string GetQueryText(Expression expression);
        public abstract object Execute(Expression expression);

}

 

復(fù)制代碼

  

  以上只是給出了一個(gè)基本實(shí)現(xiàn)IQueryProvider的抽象類,,具體實(shí)現(xiàn),我們后面講解,。

另外上面還有一個(gè)輔助類的實(shí)現(xiàn):(感興趣的可以看看,,代碼有點(diǎn)多,實(shí)際做的事情就是返回expression中指定的類型),。 

復(fù)制代碼

internal static class TypeSystem {

        internal static Type GetElementType(Type seqType) {
            Type ienum = FindIEnumerable(seqType);
            if (ienum == nullreturn seqType;
            return ienum.GetGenericArguments()[0];
        }

        private static Type FindIEnumerable(Type seqType) {
            if (seqType == null || seqType == typeof(string))
                return null;

            if (seqType.IsArray)
                return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());

            if (seqType.IsGenericType) {
                foreach (Type arg in seqType.GetGenericArguments()) {
                    Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
                    if (ienum.IsAssignableFrom(seqType)) {
                        return ienum;
                    }
                }
            }

            Type[] ifaces = seqType.GetInterfaces();
            if (ifaces != null && ifaces.Length > 0) {
                foreach (Type iface in ifaces) {
                    Type ienum = FindIEnumerable(iface);
                    if (ienum != nullreturn ienum;
                }
            }

            if (seqType.BaseType != null && seqType.BaseType != typeof(object)) {
                return FindIEnumerable(seqType.BaseType);
            }
            return null;
        }

    }

復(fù)制代碼

 

 

  今天就暫時(shí)寫到這里,,下篇接著寫。

  謝謝大家,!祝大家端午節(jié)快樂(lè),!呵呵

  版權(quán)為小洋和博客園所有,轉(zhuǎn)載請(qǐng)標(biāo)明出處給作者,。

   http://www.cnblogs.com/yanyangtian

 

  本系列文章參考: The Wayward WebLog.

 

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多