Expression.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 / Microsoft / Scripting / Ast / Expression.cs / 1305376 / Expression.cs

                            /* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Dynamic.Utils;
using System.Globalization; 
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading; 

#if SILVERLIGHT 
using System.Core; 
#endif
 
namespace System.Linq.Expressions {
    /// 
    /// The base type for all nodes in Expression Trees.
    ///  
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
    public abstract partial class Expression { 
        private delegate LambdaExpression LambdaFactory(Expression body, string name, bool tailCall, ReadOnlyCollection parameters); 

        private static readonly CacheDict _LambdaDelegateCache = new CacheDict(40); 
        private static CacheDict _LambdaFactories;

        // LINQ protected ctor from 3.5
 
#if !MICROSOFT_SCRIPTING_CORE // needs ConditionWeakTable in 4.0
 
        // For 4.0, many frequently used Expression nodes have had their memory 
        // footprint reduced by removing the Type and NodeType fields. This has
        // large performance benefits to all users of Expression Trees. 
        //
        // To support the 3.5 protected constructor, we store the fields that
        // used to be here in a ConditionalWeakTable.
 
        private class ExtensionInfo {
            public ExtensionInfo(ExpressionType nodeType, Type type) { 
                NodeType = nodeType; 
                Type = type;
            } 

            internal readonly ExpressionType NodeType;
            internal readonly Type Type;
        } 

        private static ConditionalWeakTable _legacyCtorSupportTable; 
 
        /// 
        /// Constructs a new instance of . 
        /// 
        /// The  of the .
        /// The  of the .
        [Obsolete("use a different constructor that does not take ExpressionType. Then override NodeType and Type properties to provide the values that would be specified to this constructor.")] 
        protected Expression(ExpressionType nodeType, Type type) {
            // Can't enforce anything that V1 didn't 
            if (_legacyCtorSupportTable == null) { 
                Interlocked.CompareExchange(
                    ref _legacyCtorSupportTable, 
                    new ConditionalWeakTable(),
                    null
                );
            } 

            _legacyCtorSupportTable.Add(this, new ExtensionInfo(nodeType, type)); 
        } 
#endif
 
        /// 
        /// Constructs a new instance of .
        /// 
        protected Expression() { 
        }
 
        ///  
        /// The  of the .
        ///  
        public virtual ExpressionType NodeType {
            get {
#if !MICROSOFT_SCRIPTING_CORE
                ExtensionInfo extInfo; 
                if (_legacyCtorSupportTable != null && _legacyCtorSupportTable.TryGetValue(this, out extInfo)) {
                    return extInfo.NodeType; 
                } 
#endif
                // the extension expression failed to override NodeType 
                throw Error.ExtensionNodeMustOverrideProperty("Expression.NodeType");
            }
        }
 

        ///  
        /// The  of the value represented by this . 
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] 
        public virtual Type Type {
            get {
#if !MICROSOFT_SCRIPTING_CORE
                ExtensionInfo extInfo; 
                if (_legacyCtorSupportTable != null && _legacyCtorSupportTable.TryGetValue(this, out extInfo)) {
                    return extInfo.Type; 
                } 
#endif
                // the extension expression failed to override Type 
                throw Error.ExtensionNodeMustOverrideProperty("Expression.Type");
            }
        }
 
        /// 
        /// Indicates that the node can be reduced to a simpler node. If this 
        /// returns true, Reduce() can be called to produce the reduced form. 
        /// 
        public virtual bool CanReduce { 
            get { return false; }
        }

        ///  
        /// Reduces this node to a simpler expression. If CanReduce returns
        /// true, this should return a valid expression. This method is 
        /// allowed to return another node which itself must be reduced. 
        /// 
        /// The reduced expression. 
        public virtual Expression Reduce() {
            if (CanReduce) throw Error.ReducibleMustOverrideReduce();
            return this;
        } 

        ///  
        /// Reduces the node and then calls the visitor delegate on the reduced expression. 
        /// Throws an exception if the node isn't reducible.
        ///  
        /// An instance of .
        /// The expression being visited, or an expression which should replace it in the tree.
        /// 
        /// Override this method to provide logic to walk the node's children. 
        /// A typical implementation will call visitor.Visit on each of its
        /// children, and if any of them change, should return a new copy of 
        /// itself with the modified children. 
        /// 
        protected internal virtual Expression VisitChildren(ExpressionVisitor visitor) { 
            if (!CanReduce) throw Error.MustBeReducible();
            return visitor.Visit(ReduceAndCheck());
        }
 
        /// 
        /// Dispatches to the specific visit method for this node type. For 
        /// example,  will call into 
        /// .
        ///  
        /// The visitor to visit this node with.
        /// The result of visiting this node.
        /// 
        /// This default implementation for  
        /// nodes will call .
        /// Override this method to call into a more specific method on a derived 
        /// visitor class of ExprressionVisitor. However, it should still 
        /// support unknown visitors by calling VisitExtension.
        ///  
        protected internal virtual Expression Accept(ExpressionVisitor visitor) {
            return visitor.VisitExtension(this);
        }
 
        /// 
        /// Reduces this node to a simpler expression. If CanReduce returns 
        /// true, this should return a valid expression. This method is 
        /// allowed to return another node which itself must be reduced.
        ///  
        /// The reduced expression.
        /// 
        /// Unlike Reduce, this method checks that the reduced node satisfies
        /// certain invariants. 
        /// 
        public Expression ReduceAndCheck() { 
            if (!CanReduce) throw Error.MustBeReducible(); 

            var newNode = Reduce(); 

            // 1. Reduction must return a new, non-null node
            // 2. Reduction must return a new node whose result type can be assigned to the type of the original node
            if (newNode == null || newNode == this) throw Error.MustReduceToDifferent(); 
            if (!TypeUtils.AreReferenceAssignable(Type, newNode.Type)) throw Error.ReducedNotCompatible();
            return newNode; 
        } 

        ///  
        /// Reduces the expression to a known node type (i.e. not an Extension node)
        /// or simply returns the expression if it is already a known type.
        /// 
        /// The reduced expression. 
        public Expression ReduceExtensions() {
            var node = this; 
            while (node.NodeType == ExpressionType.Extension) { 
                node = node.ReduceAndCheck();
            } 
            return node;
        }

 
        /// 
        /// Creates a  representation of the Expression. 
        ///  
        /// A  representation of the Expression.
        public override string ToString() { 
            return ExpressionStringBuilder.ExpressionToString(this);
        }

#if MICROSOFT_SCRIPTING_CORE 
        /// 
        /// Writes a  representation of the  to a . 
        ///  
        /// A  that will be used to build the string representation.
        public void DumpExpression(TextWriter writer) { 
            DebugViewWriter.WriteTo(this, writer);
        }

        ///  
        /// Creates a  representation of the Expression.
        ///  
        /// A  representation of the Expression. 
        public string DebugView {
#else 
        private string DebugView {
#endif
            get {
                using (System.IO.StringWriter writer = new System.IO.StringWriter(CultureInfo.CurrentCulture)) { 
                    DebugViewWriter.WriteTo(this, writer);
                    return writer.ToString(); 
                } 
            }
        } 

        /// 
        /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
        /// 
        /// This is called from various methods where we internally hold onto an IList of T
        /// or a readonly collection of T.  We check to see if we've already returned a 
        /// readonly collection of T and if so simply return the other one.  Otherwise we do 
        /// a thread-safe replacement of the list w/ a readonly collection which wraps it.
        /// 
        /// Ultimately this saves us from having to allocate a ReadOnlyCollection for our
        /// data types because the compiler is capable of going directly to the IList of T.
        /// 
        internal static ReadOnlyCollection ReturnReadOnly(ref IList collection) { 
            IList value = collection;
 
            // if it's already read-only just return it. 
            ReadOnlyCollection res = value as ReadOnlyCollection;
            if (res != null) { 
                return res;
            }

            // otherwise make sure only readonly collection every gets exposed 
            Interlocked.CompareExchange>(
                ref collection, 
                value.ToReadOnly(), 
                value
            ); 

            // and return it
            return (ReadOnlyCollection)collection;
        } 

        ///  
        /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T. 
        ///
        /// This is similar to the ReturnReadOnly of T. This version supports nodes which hold 
        /// onto multiple Expressions where one is typed to object.  That object field holds either
        /// an expression or a ReadOnlyCollection of Expressions.  When it holds a ReadOnlyCollection
        /// the IList which backs it is a ListArgumentProvider which uses the Expression which
        /// implements IArgumentProvider to get 2nd and additional values.  The ListArgumentProvider 
        /// continues to hold onto the 1st expression.
        /// 
        /// This enables users to get the ReadOnlyCollection w/o it consuming more memory than if 
        /// it was just an array.  Meanwhile The DLR internally avoids accessing  which would force
        /// the readonly collection to be created resulting in a typical memory savings. 
        /// 
        internal static ReadOnlyCollection ReturnReadOnly(IArgumentProvider provider, ref object collection) {
            Expression tObj = collection as Expression;
            if (tObj != null) { 
                // otherwise make sure only one readonly collection ever gets exposed
                Interlocked.CompareExchange( 
                    ref collection, 
                    new ReadOnlyCollection(new ListArgumentProvider(provider, tObj)),
                    tObj 
                );
            }

            // and return what is not guaranteed to be a readonly collection 
            return (ReadOnlyCollection)collection;
        } 
 
        /// 
        /// Helper which is used for specialized subtypes which use ReturnReadOnly(ref object, ...). 
        /// This is the reverse version of ReturnReadOnly which takes an IArgumentProvider.
        ///
        /// This is used to return the 1st argument.  The 1st argument is typed as object and either
        /// contains a ReadOnlyCollection or the Expression.  We check for the Expression and if it's 
        /// present we return that, otherwise we return the 1st element of the ReadOnlyCollection.
        ///  
        internal static T ReturnObject(object collectionOrT) where T : class { 
            T t = collectionOrT as T;
            if (t != null) { 
                return t;
            }

            return ((ReadOnlyCollection)collectionOrT)[0]; 
        }
 
        private static void RequiresCanRead(Expression expression, string paramName) { 
            if (expression == null) {
                throw new ArgumentNullException(paramName); 
            }

            // validate that we can read the node
            switch (expression.NodeType) { 
                case ExpressionType.Index:
                    IndexExpression index = (IndexExpression)expression; 
                    if (index.Indexer != null && !index.Indexer.CanRead) { 
                        throw new ArgumentException(Strings.ExpressionMustBeReadable, paramName);
                    } 
                    break;
                case ExpressionType.MemberAccess:
                    MemberExpression member = (MemberExpression)expression;
                    MemberInfo memberInfo = member.Member; 
                    if (memberInfo.MemberType == MemberTypes.Property) {
                        PropertyInfo prop = (PropertyInfo)memberInfo; 
                        if (!prop.CanRead) { 
                            throw new ArgumentException(Strings.ExpressionMustBeReadable, paramName);
                        } 
                    }
                    break;
            }
        } 

        private static void RequiresCanRead(IEnumerable items, string paramName) { 
            if (items != null) { 
                // this is called a lot, avoid allocating an enumerator if we can...
                IList listItems = items as IList; 
                if (listItems != null) {
                    for (int i = 0; i < listItems.Count; i++) {
                        RequiresCanRead(listItems[i], paramName);
                    } 
                    return;
                } 
 
                foreach (var i in items) {
                    RequiresCanRead(i, paramName); 
                }
            }
        }
        private static void RequiresCanWrite(Expression expression, string paramName) { 
            if (expression == null) {
                throw new ArgumentNullException(paramName); 
            } 

            bool canWrite = false; 
            switch (expression.NodeType) {
                case ExpressionType.Index:
                    IndexExpression index = (IndexExpression)expression;
                    if (index.Indexer != null) { 
                        canWrite = index.Indexer.CanWrite;
                    } else { 
                        canWrite = true; 
                    }
                    break; 
                case ExpressionType.MemberAccess:
                    MemberExpression member = (MemberExpression)expression;
                    switch (member.Member.MemberType) {
                        case MemberTypes.Property: 
                            PropertyInfo prop = (PropertyInfo)member.Member;
                            canWrite = prop.CanWrite; 
                            break; 
                        case MemberTypes.Field:
                            FieldInfo field = (FieldInfo)member.Member; 
                            canWrite = !(field.IsInitOnly || field.IsLiteral);
                            break;
                    }
                    break; 
                case ExpressionType.Parameter:
                    canWrite = true; 
                    break; 
            }
 
            if (!canWrite) {
                throw new ArgumentException(Strings.ExpressionMustBeWriteable, paramName);
            }
        } 
    }
} 

// 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