SequenceQuery.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Linq / SequenceQuery.cs / 1305376 / SequenceQuery.cs

                            using System; 
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq.Expressions; 
using System.Reflection;
using System.Text; 
 
// Include Silverlight's managed resources
#if SILVERLIGHT 
using System.Core;
#endif //SILVERLIGHT

namespace System.Linq { 

    // Must remain public for Silverlight 
    public abstract class EnumerableQuery { 
        internal abstract Expression Expression { get; }
        internal abstract IEnumerable Enumerable { get; } 
        internal static IQueryable Create(Type elementType, IEnumerable sequence){
            Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType);
#if SILVERLIGHT
            return (IQueryable) Activator.CreateInstance(seqType, sequence); 
#else
            return (IQueryable) Activator.CreateInstance(seqType, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, new object[] {sequence}, null); 
#endif //SILVERLIGHT 
        }
 
        internal static IQueryable Create(Type elementType, Expression expression) {
            Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType);
#if SILVERLIGHT
            return (IQueryable) Activator.CreateInstance(seqType, expression); 
#else
            return (IQueryable) Activator.CreateInstance(seqType, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, new object[] {expression}, null); 
#endif //SILVERLIGHT 
        }
    } 

    // Must remain public for Silverlight
    public class EnumerableQuery : EnumerableQuery, IOrderedQueryable, IQueryable, IQueryProvider, IEnumerable, IEnumerable {
        Expression expression; 
        IEnumerable enumerable;
 
        IQueryProvider IQueryable.Provider { 
            get{
               return (IQueryProvider)this; 
            }
        }

        // Must remain public for Silverlight 
        public EnumerableQuery(IEnumerable enumerable) {
            this.enumerable = enumerable; 
            this.expression = Expression.Constant(this); 
        }
 
        // Must remain public for Silverlight
        public EnumerableQuery(Expression expression) {
            this.expression = expression;
        } 

        internal override Expression Expression { 
            get { return this.expression; } 
        }
 
        internal override IEnumerable Enumerable {
            get { return this.enumerable; }
        }
 
        Expression IQueryable.Expression {
            get { return this.expression; } 
        } 

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

        IQueryable IQueryProvider.CreateQuery(Expression expression){ 
            if (expression == null)
                throw Error.ArgumentNull("expression"); 
            Type iqType = TypeHelper.FindGenericType(typeof(IQueryable<>), expression.Type); 
            if (iqType == null)
                throw Error.ArgumentNotValid("expression"); 
            return EnumerableQuery.Create(iqType.GetGenericArguments()[0], expression);
        }

        IQueryable IQueryProvider.CreateQuery(Expression expression){ 
            if (expression == null)
                throw Error.ArgumentNull("expression"); 
            if (!typeof(IQueryable).IsAssignableFrom(expression.Type)){ 
                throw Error.ArgumentNotValid("expression");
            } 
            return new EnumerableQuery(expression);
        }

        // Baselining as Safe for Mix demo so that interface can be transparent. Marking this 
        // critical (which was the original annotation when porting to silverlight) would violate
        // fxcop security rules if the interface isn't also critical. However, transparent code 
        // can't access this anyway for Mix since we're not exposing AsQueryable(). 
        // [....]: the above assertion no longer holds. Now making AsQueryable() public again
        // the security fallout of which will need to be re-examined. 
        object IQueryProvider.Execute(Expression expression){
            if (expression == null)
                throw Error.ArgumentNull("expression");
            Type execType = typeof(EnumerableExecutor<>).MakeGenericType(expression.Type); 
            return EnumerableExecutor.Create(expression).ExecuteBoxed();
        } 
 
        // see above
        S IQueryProvider.Execute(Expression expression){ 
            if (expression == null)
                throw Error.ArgumentNull("expression");
            if (!typeof(S).IsAssignableFrom(expression.Type))
                throw Error.ArgumentNotValid("expression"); 
            return new EnumerableExecutor(expression).Execute();
        } 
 
        IEnumerator IEnumerable.GetEnumerator() {
            return this.GetEnumerator(); 
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return this.GetEnumerator(); 
        }
 
        IEnumerator GetEnumerator() { 
            if (this.enumerable == null) {
                EnumerableRewriter rewriter = new EnumerableRewriter(); 
                Expression body = rewriter.Visit(this.expression);
                Expression>> f = Expression.Lambda>>(body, (IEnumerable)null);
                this.enumerable = f.Compile()();
            } 
            return this.enumerable.GetEnumerator();
        } 
 
        public override string ToString() {
            ConstantExpression c = this.expression as ConstantExpression; 
            if (c != null && c.Value == this) {
                if (this.enumerable != null)
                    return this.enumerable.ToString();
                return "null"; 
            }
            return this.expression.ToString(); 
        } 
    }
 
    // Must remain public for Silverlight
    public abstract class EnumerableExecutor {
        internal abstract object ExecuteBoxed();
 
        internal static EnumerableExecutor Create(Expression expression) {
            Type execType = typeof(EnumerableExecutor<>).MakeGenericType(expression.Type); 
#if SILVERLIGHT 
            return (EnumerableExecutor)Activator.CreateInstance(execType, expression);
#else 
            return (EnumerableExecutor)Activator.CreateInstance(execType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { expression }, null);
#endif //SILVERLIGHT
        }
    } 

    // Must remain public for Silverlight 
    public class EnumerableExecutor : EnumerableExecutor{ 
        Expression expression;
        Func func; 

        // Must remain public for Silverlight
        public EnumerableExecutor(Expression expression){
            this.expression = expression; 
        }
 
        internal override object ExecuteBoxed() { 
            return this.Execute();
        } 

        internal T Execute(){
            if (this.func == null){
                EnumerableRewriter rewriter = new EnumerableRewriter(); 
                Expression body = rewriter.Visit(this.expression);
                Expression> f = Expression.Lambda>(body, (IEnumerable)null); 
                this.func = f.Compile(); 
            }
            return this.func(); 
        }
    }

    // 
    internal class EnumerableRewriter : OldExpressionVisitor {
 
        internal EnumerableRewriter() { 
        }
 
        internal override Expression VisitMethodCall(MethodCallExpression m) {
            Expression obj = this.Visit(m.Object);
            ReadOnlyCollection args = this.VisitExpressionList(m.Arguments);
 
            // check for args changed
            if (obj != m.Object || args != m.Arguments) { 
                Expression[] argArray = args.ToArray(); 
                Type[] typeArgs = (m.Method.IsGenericMethod) ? m.Method.GetGenericArguments() : null;
 
                if ((m.Method.IsStatic || m.Method.DeclaringType.IsAssignableFrom(obj.Type))
                    && ArgsMatch(m.Method, args, typeArgs)) {
                    // current method is still valid
                    return Expression.Call(obj, m.Method, args); 
                }
                else if (m.Method.DeclaringType == typeof(Queryable)) { 
                    // convert Queryable method to Enumerable method 
                    MethodInfo seqMethod = FindEnumerableMethod(m.Method.Name, args, typeArgs);
                    args = this.FixupQuotedArgs(seqMethod, args); 
                    return Expression.Call(obj, seqMethod, args);
                }
                else {
                    // rebind to new method 
                    BindingFlags flags = BindingFlags.Static | (m.Method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
                    MethodInfo method = FindMethod(m.Method.DeclaringType, m.Method.Name, args, typeArgs, flags); 
                    args = this.FixupQuotedArgs(method, args); 
                    return Expression.Call(obj, method, args);
                } 
            }
            return m;
        }
 
        private ReadOnlyCollection FixupQuotedArgs(MethodInfo mi, ReadOnlyCollection argList) {
            ParameterInfo[] pis = mi.GetParameters(); 
            if (pis.Length > 0) { 
                List newArgs = null;
                for (int i = 0, n = pis.Length; i < n; i++) { 
                    Expression arg = argList[i];
                    ParameterInfo pi = pis[i];
                    arg = FixupQuotedExpression(pi.ParameterType, arg);
                    if (newArgs == null && arg != argList[i]) { 
                        newArgs = new List(argList.Count);
                        for (int j = 0; j < i; j++) { 
                            newArgs.Add(argList[j]); 
                        }
                    } 
                    if (newArgs != null) {
                        newArgs.Add(arg);
                    }
                } 
                if (newArgs != null)
                    argList = newArgs.ToReadOnlyCollection(); 
            } 
            return argList;
        } 

        private Expression FixupQuotedExpression(Type type, Expression expression) {
            Expression expr = expression;
            while (true) { 
                if (type.IsAssignableFrom(expr.Type))
                    return expr; 
                if (expr.NodeType != ExpressionType.Quote) 
                    break;
                expr = ((UnaryExpression)expr).Operand; 
            }
            if (!type.IsAssignableFrom(expr.Type) && type.IsArray && expr.NodeType == ExpressionType.NewArrayInit) {
                Type strippedType = StripExpression(expr.Type);
                if (type.IsAssignableFrom(strippedType)) { 
                    Type elementType = type.GetElementType();
                    NewArrayExpression na = (NewArrayExpression)expr; 
                    List exprs = new List(na.Expressions.Count); 
                    for (int i = 0, n = na.Expressions.Count; i < n; i++) {
                        exprs.Add(this.FixupQuotedExpression(elementType, na.Expressions[i])); 
                    }
                    expression = Expression.NewArrayInit(elementType, exprs);
                }
            } 
            return expression;
        } 
 
        internal override Expression VisitLambda(LambdaExpression lambda) {
            return lambda; 
        }

        private static Type GetPublicType(Type t)
        { 
            // If we create a constant explicitly typed to be a private nested type,
            // such as Lookup<,>.Grouping or a compiler-generated iterator class, then 
            // we cannot use the expression tree in a context which has only execution 
            // permissions.  We should endeavour to translate constants into
            // new constants which have public types. 
            if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Lookup<,>.Grouping))
                return typeof(IGrouping<,>).MakeGenericType(t.GetGenericArguments());
            if (!t.IsNestedPrivate)
                return t; 
            foreach (Type iType in t.GetInterfaces())
            { 
                if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 
                    return iType;
            } 
            if (typeof(IEnumerable).IsAssignableFrom(t))
                return typeof(IEnumerable);
            return t;
        } 

        internal override Expression VisitConstant(ConstantExpression c) { 
            EnumerableQuery sq = c.Value as EnumerableQuery; 
            if (sq != null) {
                if (sq.Enumerable != null) 
                {
                    Type t = GetPublicType(sq.Enumerable.GetType());
                    return Expression.Constant(sq.Enumerable, t);
                } 
                return this.Visit(sq.Expression);
            } 
            return c; 
        }
 
        internal override Expression VisitParameter(ParameterExpression p) {
            return p;
        }
 
        private static ILookup _seqMethods;
        static MethodInfo FindEnumerableMethod(string name, ReadOnlyCollection args, params Type[] typeArgs) { 
            if (_seqMethods == null) { 
                _seqMethods = typeof(Enumerable).GetMethods(BindingFlags.Static|BindingFlags.Public).ToLookup(m => m.Name);
            } 
            MethodInfo mi = _seqMethods[name].FirstOrDefault(m => ArgsMatch(m, args, typeArgs));
            if (mi == null)
                throw Error.NoMethodOnTypeMatchingArguments(name, typeof(Enumerable));
            if (typeArgs != null) 
                return mi.MakeGenericMethod(typeArgs);
            return mi; 
        } 

        internal static MethodInfo FindMethod(Type type, string name, ReadOnlyCollection args, Type[] typeArgs, BindingFlags flags) { 
            MethodInfo[] methods = type.GetMethods(flags).Where(m => m.Name == name).ToArray();
            if (methods.Length == 0)
                throw Error.NoMethodOnType(name, type);
            MethodInfo mi = methods.FirstOrDefault(m => ArgsMatch(m, args, typeArgs)); 
            if (mi == null)
                throw Error.NoMethodOnTypeMatchingArguments(name, type); 
            if (typeArgs != null) 
                return mi.MakeGenericMethod(typeArgs);
            return mi; 
        }

        private static bool ArgsMatch(MethodInfo m, ReadOnlyCollection args, Type[] typeArgs) {
            ParameterInfo[] mParams = m.GetParameters(); 
            if (mParams.Length != args.Count)
                return false; 
            if (!m.IsGenericMethod && typeArgs != null && typeArgs.Length > 0) { 
                return false;
            } 
            if (!m.IsGenericMethodDefinition && m.IsGenericMethod && m.ContainsGenericParameters) {
                m = m.GetGenericMethodDefinition();
            }
            if (m.IsGenericMethodDefinition) { 
                if (typeArgs == null || typeArgs.Length == 0)
                    return false; 
                if (m.GetGenericArguments().Length != typeArgs.Length) 
                    return false;
                m = m.MakeGenericMethod(typeArgs); 
                mParams = m.GetParameters();
            }
            for (int i = 0, n = args.Count; i < n; i++) {
                Type parameterType = mParams[i].ParameterType; 
                if (parameterType == null)
                    return false; 
                if (parameterType.IsByRef) 
                    parameterType = parameterType.GetElementType();
                Expression arg = args[i]; 
                if (!parameterType.IsAssignableFrom(arg.Type)) {
                    if (arg.NodeType == ExpressionType.Quote) {
                        arg = ((UnaryExpression)arg).Operand;
                    } 
                    if (!parameterType.IsAssignableFrom(arg.Type) &&
                        !parameterType.IsAssignableFrom(StripExpression(arg.Type))) { 
                        return false; 
                    }
                } 
            }
            return true;
        }
 
        private static Type StripExpression(Type type) {
            bool isArray = type.IsArray; 
            Type tmp = isArray ? type.GetElementType() : type; 
            Type eType = TypeHelper.FindGenericType(typeof(Expression<>), tmp);
            if (eType != null) 
                tmp = eType.GetGenericArguments()[0];
            if (isArray) {
                int rank = type.GetArrayRank();
                return (rank == 1) ? tmp.MakeArrayType() : tmp.MakeArrayType(rank); 
            }
            return type; 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK