InitializerFacet.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / InitializerFacet.cs / 2 / InitializerFacet.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
//--------------------------------------------------------------------- 
 
using System.Data.Metadata.Edm;
using System.Collections.Generic; 
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
using System.Linq; 
using System.Collections;
using System.Data.Objects.DataClasses; 
using System.Threading; 
using System.Globalization;
using System.Security.Permissions; 
using System.Security;
using System.Data.Common.Internal.Materialization;
using System.Data.Query.InternalTrees;
using System.Text; 
namespace System.Data.Objects.ELinq
{ 
    ///  
    /// Facet encapsulating information necessary to initialize a LINQ projection
    /// result. 
    /// 
    internal abstract class InitializerMetadata : IEquatable
    {
        internal readonly Type ClrType; 
        private static long s_identifier;
        internal readonly string Identity; 
        private static readonly string s_identifierPrefix = typeof(InitializerMetadata).Name; 

        private InitializerMetadata(Type clrType) 
        {
            Debug.Assert(null != clrType);
            ClrType = clrType;
            Identity = s_identifierPrefix + Interlocked.Increment(ref s_identifier).ToString(CultureInfo.InvariantCulture); 
        }
 
        // Gets the kind of this initializer (grouping, row, etc.) 
        internal abstract InitializerMetadataKind Kind { get; }
 
        // Attempts to retrieve the initializer facet from a type usage
        internal static bool TryGetInitializerMetadata(TypeUsage typeUsage, out InitializerMetadata initializerMetadata)
        {
            initializerMetadata = null; 
            if (BuiltInTypeKind.RowType == typeUsage.EdmType.BuiltInTypeKind)
            { 
                initializerMetadata = ((RowType)typeUsage.EdmType).InitializerMetadata; 
            }
            return null != initializerMetadata; 
        }

        // Initializes an initializer for an IGrouping return type
        // Requires: resultType is IGrouping instance. 
        internal static InitializerMetadata CreateGroupingInitializer(EdmItemCollection itemCollection, Type resultType)
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new GroupingInitializerMetadata(resultType)); 
        }
 
        // Initializes an initializer for a MemberInit expression
        internal static InitializerMetadata CreateProjectionInitializer(EdmItemCollection itemCollection, MemberInitExpression initExpression,
            MemberInfo[] members)
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new ProjectionInitializerMetadata(initExpression, members));
        } 
 
        // Initializes an initializer for a New expression
        internal static InitializerMetadata CreateProjectionInitializer(EdmItemCollection itemCollection, NewExpression newExpression) 
        {
            return itemCollection.GetCanonicalInitializerMetadata(new ProjectionNewMetadata(newExpression));
        }
 
        // Initializes an initializer for a New expression with no properties
        internal static InitializerMetadata CreateEmptyProjectionInitializer(EdmItemCollection itemCollection, NewExpression newExpression) 
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new EmptyProjectionNewMetadata(newExpression));
        } 

        // Creates metadata for entity collection materialization
        internal static InitializerMetadata CreateEntityCollectionInitializer(EdmItemCollection itemCollection, Type type, NavigationProperty navigationProperty)
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new EntityCollectionInitializerMetadata(type, navigationProperty));
        } 
 
        internal virtual void AppendColumnMapKey(ColumnMapKeyBuilder builder)
        { 
            // by default, the type is sufficient (more information is needed for EntityCollection and initializers)
            builder.Append("CLR-", this.ClrType);
        }
 
        public override bool Equals(object obj)
        { 
            Debug.Fail("use typed Equals method only"); 
            return Equals(obj as InitializerMetadata);
        } 

        public bool Equals(InitializerMetadata other)
        {
            Debug.Assert(null != other, "must not use a null key"); 
            if (object.ReferenceEquals(this, other)) { return true; }
            if (this.Kind != other.Kind) { return false; } 
            if (!this.ClrType.Equals(other.ClrType)) { return false; } 
            return IsStructurallyEquivalent(other);
        } 

        public override int GetHashCode()
        {
            return ClrType.GetHashCode(); 
        }
 
        ///  
        /// Requires: other has the same type as this and refers to the same CLR type
        /// Determine whether this Metadata is compatible with the other based on record layout. 
        /// 
        protected virtual bool IsStructurallyEquivalent(InitializerMetadata other)
        {
            return true; 
        }
 
        ///  
        /// Produces an expression initializing an instance of ClrType (given emitters for input
        /// columns) 
        /// 
        internal abstract Expression Emit(Translator translator, List propertyTranslatorResults);

        ///  
        /// Yields expected types for input columns. Null values are returned for children
        /// whose type is irrelevant to the initializer. 
        ///  
        internal abstract IEnumerable GetChildTypes();
 
        /// 
        /// return a list of propertyReader expressions from an array of translator results.
        /// 
        ///  
        /// 
        protected static List GetPropertyReaders(List propertyTranslatorResults) 
        { 
            List propertyReaders = propertyTranslatorResults.Select(s => s.Expression).ToList();
            return propertyReaders; 
        }

        /// 
        /// Implementation of IGrouping that can be initialized using the standard 
        /// initializer pattern supported by ELinq
        ///  
        /// Type of key 
        /// Type of record
        private class Grouping : IGrouping 
        {
            public Grouping(K key, IEnumerable group)
            {
                _key = key; 
                _group = group;
            } 
 
            private readonly K _key;
            private readonly IEnumerable _group; 

            public K Key
            {
                get { return _key; } 
            }
 
            public IEnumerable Group 
            {
                get { return _group; } 
            }

            IEnumerator IEnumerable.GetEnumerator()
            { 
                if (null == _group)
                { 
                    yield break; 
                }
                foreach (T member in _group) 
                {
                    yield return member;
                }
            } 

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
            { 
                return ((IEnumerable)this).GetEnumerator();
            } 
        }

        /// 
        /// Metadata for grouping initializer. 
        /// 
        private class GroupingInitializerMetadata : InitializerMetadata 
        { 
            internal GroupingInitializerMetadata(Type type)
                : base(type) 
            {
            }

            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.Grouping; } } 

            internal override Expression Emit(Translator translator, List propertyTranslatorResults) 
            { 
                // Create expression of the form:
                // new Grouping(children[0], children[1]) 

                // Collect information...
                Debug.Assert(ClrType.IsGenericType &&
                    typeof(IGrouping<,>).Equals(ClrType.GetGenericTypeDefinition())); 
                Debug.Assert(propertyTranslatorResults.Count == 2);
                Type keyType = this.ClrType.GetGenericArguments()[0]; 
                Type groupElementType = this.ClrType.GetGenericArguments()[1]; 
                Type groupType = typeof(Grouping<,>).MakeGenericType(keyType, groupElementType);
                ConstructorInfo constructor = groupType.GetConstructors().Single(); 

                // new Grouping(children[0], children[1])
                Expression newGrouping = Expression.Convert(Expression.New(constructor, GetPropertyReaders(propertyTranslatorResults)), this.ClrType);
 
                return newGrouping;
            } 
 
            internal override IEnumerable GetChildTypes()
            { 
                // Collect information...
                Debug.Assert(ClrType.IsGenericType &&
                    typeof(IGrouping<,>).Equals(ClrType.GetGenericTypeDefinition()));
                Type keyType = this.ClrType.GetGenericArguments()[0]; 
                Type groupElementType = this.ClrType.GetGenericArguments()[1];
 
                // key 
                yield return keyType;
                // group 
                yield return typeof(IEnumerable<>).MakeGenericType(groupElementType);
            }
        }
 
        /// 
        /// Metadata for anonymous type materialization. 
        ///  
        private class ProjectionNewMetadata : InitializerMetadata
        { 
            internal ProjectionNewMetadata(NewExpression newExpression)
                : base(newExpression.Type)
            {
                Debug.Assert(null != newExpression); 
                _newExpression = newExpression;
            } 
 
            private readonly NewExpression _newExpression;
 
            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.ProjectionNew; } }

            protected override bool IsStructurallyEquivalent(InitializerMetadata other)
            { 
                // caller must ensure the type matches
                ProjectionNewMetadata otherProjection = (ProjectionNewMetadata)other; 
                if (this._newExpression.Members.Count != otherProjection._newExpression.Members.Count) 
                {
                    return false; 
                }

                for (int i = 0; i < this._newExpression.Members.Count; i++)
                { 
                    MemberInfo thisMember = this._newExpression.Members[i];
                    MemberInfo otherMember = otherProjection._newExpression.Members[i]; 
                    if (!thisMember.Equals(otherMember)) 
                    {
                        return false; 
                    }
                }

                return true; 
            }
 
            internal override Expression Emit(Translator translator, List propertyTranslatorResults) 
            {
                // Create expression of the form: 
                // _newExpression(children)

                // (ClrType)null
                Expression nullProjection = Expression.Constant(null, this.ClrType); 

                // _newExpression with members rebound 
                Expression newProjection = Expression.New(_newExpression.Constructor, GetPropertyReaders(propertyTranslatorResults)); 

                // _newExpression with members rebound to constants (used for security check) 
                Expression constantProjection = Expression.New(_newExpression.Constructor,
                    propertyTranslatorResults.Select(child => (Expression)Expression.Constant(TypeSystem.GetDefaultValue(child.Expression.Type), child.Expression.Type)));
                translator.RegisterUserExpression(constantProjection);
 
                // condition
                return newProjection; 
            } 

            internal override IEnumerable GetChildTypes() 
            {
                // return all argument types
                return _newExpression.Arguments.Select(arg => arg.Type);
            } 

            internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder) 
            { 
                base.AppendColumnMapKey(builder);
                builder.Append(_newExpression.Constructor.ToString()); 
                foreach (var member in _newExpression.Members ?? Enumerable.Empty())
                {
                    builder.Append("DT", member.DeclaringType);
                    builder.Append("." + member.Name); 
                }
            } 
        } 

        private class EmptyProjectionNewMetadata : ProjectionNewMetadata 
        {
            internal EmptyProjectionNewMetadata(NewExpression newExpression)
                : base(newExpression)
            { 
            }
            internal override Expression Emit(Translator translator, List propertyReaders) 
            { 
                // ignore sentinel column
                return base.Emit(translator, new List()); 
            }
            internal override IEnumerable GetChildTypes()
            {
                // ignore sentinel column 
                yield return null;
            } 
        } 

        ///  
        /// Metadata for standard projection initializers.
        /// 
        private class ProjectionInitializerMetadata : InitializerMetadata
        { 
            internal ProjectionInitializerMetadata(MemberInitExpression initExpression, MemberInfo[] members)
                : base(initExpression.Type) 
            { 
                Debug.Assert(null != initExpression);
                Debug.Assert(null != members); 
                _initExpression = initExpression;
                _members = members;
            }
 
            private readonly MemberInitExpression _initExpression;
            private readonly MemberInfo[] _members; 
 
            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.ProjectionInitializer; } }
 
            protected override bool IsStructurallyEquivalent(InitializerMetadata other)
            {
                // caller must ensure the type matches
                ProjectionInitializerMetadata otherProjection = (ProjectionInitializerMetadata)other; 
                if (this._initExpression.Bindings.Count != otherProjection._initExpression.Bindings.Count)
                { 
                    return false; 
                }
 
                for (int i = 0; i < this._initExpression.Bindings.Count; i++)
                {
                    MemberBinding thisBinding = this._initExpression.Bindings[i];
                    MemberBinding otherBinding = otherProjection._initExpression.Bindings[i]; 
                    if (!thisBinding.Member.Equals(otherBinding.Member))
                    { 
                        return false; 
                    }
                } 

                return true;
            }
 
            internal override Expression Emit(Translator translator, List propertyReaders)
            { 
                // Create expression of the form: 
                // _initExpression(children)
 
                // create member bindings (where values are taken from children)
                MemberBinding[] memberBindings = new MemberBinding[_initExpression.Bindings.Count];
                MemberBinding[] constantMemberBindings = new MemberBinding[memberBindings.Length];
                for (int i = 0; i < memberBindings.Length; i++) 
                {
                    MemberBinding originalBinding = _initExpression.Bindings[i]; 
                    Expression value = propertyReaders[i].Expression; 
                    MemberBinding newBinding = Expression.Bind(originalBinding.Member, value);
                    MemberBinding constantBinding = Expression.Bind(originalBinding.Member, Expression.Constant( 
                        TypeSystem.GetDefaultValue(value.Type), value.Type));
                    memberBindings[i] = newBinding;
                    constantMemberBindings[i] = constantBinding;
                } 

                Expression newProjection = Expression.MemberInit(_initExpression.NewExpression, memberBindings); 
                Expression constantProjection = Expression.MemberInit(_initExpression.NewExpression, constantMemberBindings); 

                translator.RegisterUserExpression(constantProjection); 

                return newProjection;
            }
 
            internal override IEnumerable GetChildTypes()
            { 
                // return all argument types 
                foreach (var binding in _initExpression.Bindings)
                { 
                    // determine member type
                    Type memberType;
                    string name;
                    TypeSystem.PropertyOrField(binding.Member, out name, out memberType); 
                    yield return memberType;
                } 
            } 

            internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder) 
            {
                base.AppendColumnMapKey(builder);
                foreach (var binding in _initExpression.Bindings)
                { 
                    builder.Append(",", binding.Member.DeclaringType);
                    builder.Append("." + binding.Member.Name); 
                } 
            }
        } 

        /// 
        /// Metadata for entity collection initializer.
        ///  
        private class EntityCollectionInitializerMetadata : InitializerMetadata
        { 
            internal EntityCollectionInitializerMetadata(Type type, NavigationProperty navigationProperty) 
                : base(type)
            { 
                Debug.Assert(null != navigationProperty);
                _navigationProperty = navigationProperty;
            }
 
            private readonly NavigationProperty _navigationProperty;
 
            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.EntityCollection; } } 

            ///  
            /// Make sure the other metadata instance generates the same property
            /// (otherwise, we get incorrect behavior where multiple nav props return
            /// the same type)
            ///  
            protected override bool IsStructurallyEquivalent(InitializerMetadata other)
            { 
                // caller must ensure the type matches 
                EntityCollectionInitializerMetadata otherInitializer = (EntityCollectionInitializerMetadata)other;
                return this._navigationProperty.Equals(otherInitializer._navigationProperty); 
            }

            private static readonly MethodInfo s_createEntityCollectionMethod = typeof(EntityCollectionInitializerMetadata).GetMethod("CreateEntityCollection",
                BindingFlags.Static | BindingFlags.Public); 

            internal override Expression Emit(Translator translator, List propertyTranslatorResults) 
            { 
                Debug.Assert(propertyTranslatorResults.Count > 1, "no properties?");
                Debug.Assert(propertyTranslatorResults[1] is CollectionTranslatorResult, "not a collection?"); 

                Type elementType = GetElementType();
                MethodInfo createEntityCollectionMethod = s_createEntityCollectionMethod.MakeGenericMethod(elementType);
 
                Expression shaper = Translator.Shaper_Parameter;
                Expression owner = propertyTranslatorResults[0].Expression; 
 
                CollectionTranslatorResult collectionResult = propertyTranslatorResults[1] as CollectionTranslatorResult;
 
                Expression coordinator = collectionResult.ExpressionToGetCoordinator;

                // CreateEntityCollection(shaper, owner, elements, relationshipName, targetRoleName)
                Expression result = Expression.Call(createEntityCollectionMethod, 
                    shaper, owner, coordinator, Expression.Constant(_navigationProperty.RelationshipType.FullName), Expression.Constant(_navigationProperty.ToEndMember.Name));
 
                return result; 
            }
 
            public static EntityCollection CreateEntityCollection(Shaper state, IEntityWithRelationships owner, Coordinator coordinator, string relationshipName, string targetRoleName)
                where T : class, IEntityWithRelationships
            {
                if (null == owner) 
                {
                    return null; 
                } 
                else
                { 
                    EntityCollection result = owner.RelationshipManager.GetRelatedCollection(relationshipName, targetRoleName);
                    // register a handler for deferred loading (when the nested result has been consumed)
                    coordinator.RegisterCloseHandler((readerState, elements) => result.Load(elements, readerState.MergeOption));
                    return result; 
                }
            } 
 
            internal override IEnumerable GetChildTypes()
            { 
                Type elementType = GetElementType();
                yield return null; // defer in determining entity type...
                yield return typeof(IEnumerable<>).MakeGenericType(elementType);
            } 

 
            internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder) 
            {
                base.AppendColumnMapKey(builder); 
                builder.Append(",NP" + _navigationProperty.Name);
                builder.Append(",AT", _navigationProperty.DeclaringType);
            }
 
            private Type GetElementType()
            { 
                if (!this.ClrType.IsGenericType || !typeof(EntityCollection<>).Equals(ClrType.GetGenericTypeDefinition())) 
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnexpectedTypeForNavigationProperty( 
                        _navigationProperty,
                        typeof(EntityCollection<>),
                        ClrType));
                } 
                Type elementType = this.ClrType.GetGenericArguments()[0];
                return elementType; 
            } 
        }
 
    }

    internal enum InitializerMetadataKind
    { 
        Grouping,
        ProjectionNew, 
        ProjectionInitializer, 
        EntityCollection,
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
//--------------------------------------------------------------------- 
 
using System.Data.Metadata.Edm;
using System.Collections.Generic; 
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
using System.Linq; 
using System.Collections;
using System.Data.Objects.DataClasses; 
using System.Threading; 
using System.Globalization;
using System.Security.Permissions; 
using System.Security;
using System.Data.Common.Internal.Materialization;
using System.Data.Query.InternalTrees;
using System.Text; 
namespace System.Data.Objects.ELinq
{ 
    ///  
    /// Facet encapsulating information necessary to initialize a LINQ projection
    /// result. 
    /// 
    internal abstract class InitializerMetadata : IEquatable
    {
        internal readonly Type ClrType; 
        private static long s_identifier;
        internal readonly string Identity; 
        private static readonly string s_identifierPrefix = typeof(InitializerMetadata).Name; 

        private InitializerMetadata(Type clrType) 
        {
            Debug.Assert(null != clrType);
            ClrType = clrType;
            Identity = s_identifierPrefix + Interlocked.Increment(ref s_identifier).ToString(CultureInfo.InvariantCulture); 
        }
 
        // Gets the kind of this initializer (grouping, row, etc.) 
        internal abstract InitializerMetadataKind Kind { get; }
 
        // Attempts to retrieve the initializer facet from a type usage
        internal static bool TryGetInitializerMetadata(TypeUsage typeUsage, out InitializerMetadata initializerMetadata)
        {
            initializerMetadata = null; 
            if (BuiltInTypeKind.RowType == typeUsage.EdmType.BuiltInTypeKind)
            { 
                initializerMetadata = ((RowType)typeUsage.EdmType).InitializerMetadata; 
            }
            return null != initializerMetadata; 
        }

        // Initializes an initializer for an IGrouping return type
        // Requires: resultType is IGrouping instance. 
        internal static InitializerMetadata CreateGroupingInitializer(EdmItemCollection itemCollection, Type resultType)
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new GroupingInitializerMetadata(resultType)); 
        }
 
        // Initializes an initializer for a MemberInit expression
        internal static InitializerMetadata CreateProjectionInitializer(EdmItemCollection itemCollection, MemberInitExpression initExpression,
            MemberInfo[] members)
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new ProjectionInitializerMetadata(initExpression, members));
        } 
 
        // Initializes an initializer for a New expression
        internal static InitializerMetadata CreateProjectionInitializer(EdmItemCollection itemCollection, NewExpression newExpression) 
        {
            return itemCollection.GetCanonicalInitializerMetadata(new ProjectionNewMetadata(newExpression));
        }
 
        // Initializes an initializer for a New expression with no properties
        internal static InitializerMetadata CreateEmptyProjectionInitializer(EdmItemCollection itemCollection, NewExpression newExpression) 
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new EmptyProjectionNewMetadata(newExpression));
        } 

        // Creates metadata for entity collection materialization
        internal static InitializerMetadata CreateEntityCollectionInitializer(EdmItemCollection itemCollection, Type type, NavigationProperty navigationProperty)
        { 
            return itemCollection.GetCanonicalInitializerMetadata(new EntityCollectionInitializerMetadata(type, navigationProperty));
        } 
 
        internal virtual void AppendColumnMapKey(ColumnMapKeyBuilder builder)
        { 
            // by default, the type is sufficient (more information is needed for EntityCollection and initializers)
            builder.Append("CLR-", this.ClrType);
        }
 
        public override bool Equals(object obj)
        { 
            Debug.Fail("use typed Equals method only"); 
            return Equals(obj as InitializerMetadata);
        } 

        public bool Equals(InitializerMetadata other)
        {
            Debug.Assert(null != other, "must not use a null key"); 
            if (object.ReferenceEquals(this, other)) { return true; }
            if (this.Kind != other.Kind) { return false; } 
            if (!this.ClrType.Equals(other.ClrType)) { return false; } 
            return IsStructurallyEquivalent(other);
        } 

        public override int GetHashCode()
        {
            return ClrType.GetHashCode(); 
        }
 
        ///  
        /// Requires: other has the same type as this and refers to the same CLR type
        /// Determine whether this Metadata is compatible with the other based on record layout. 
        /// 
        protected virtual bool IsStructurallyEquivalent(InitializerMetadata other)
        {
            return true; 
        }
 
        ///  
        /// Produces an expression initializing an instance of ClrType (given emitters for input
        /// columns) 
        /// 
        internal abstract Expression Emit(Translator translator, List propertyTranslatorResults);

        ///  
        /// Yields expected types for input columns. Null values are returned for children
        /// whose type is irrelevant to the initializer. 
        ///  
        internal abstract IEnumerable GetChildTypes();
 
        /// 
        /// return a list of propertyReader expressions from an array of translator results.
        /// 
        ///  
        /// 
        protected static List GetPropertyReaders(List propertyTranslatorResults) 
        { 
            List propertyReaders = propertyTranslatorResults.Select(s => s.Expression).ToList();
            return propertyReaders; 
        }

        /// 
        /// Implementation of IGrouping that can be initialized using the standard 
        /// initializer pattern supported by ELinq
        ///  
        /// Type of key 
        /// Type of record
        private class Grouping : IGrouping 
        {
            public Grouping(K key, IEnumerable group)
            {
                _key = key; 
                _group = group;
            } 
 
            private readonly K _key;
            private readonly IEnumerable _group; 

            public K Key
            {
                get { return _key; } 
            }
 
            public IEnumerable Group 
            {
                get { return _group; } 
            }

            IEnumerator IEnumerable.GetEnumerator()
            { 
                if (null == _group)
                { 
                    yield break; 
                }
                foreach (T member in _group) 
                {
                    yield return member;
                }
            } 

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
            { 
                return ((IEnumerable)this).GetEnumerator();
            } 
        }

        /// 
        /// Metadata for grouping initializer. 
        /// 
        private class GroupingInitializerMetadata : InitializerMetadata 
        { 
            internal GroupingInitializerMetadata(Type type)
                : base(type) 
            {
            }

            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.Grouping; } } 

            internal override Expression Emit(Translator translator, List propertyTranslatorResults) 
            { 
                // Create expression of the form:
                // new Grouping(children[0], children[1]) 

                // Collect information...
                Debug.Assert(ClrType.IsGenericType &&
                    typeof(IGrouping<,>).Equals(ClrType.GetGenericTypeDefinition())); 
                Debug.Assert(propertyTranslatorResults.Count == 2);
                Type keyType = this.ClrType.GetGenericArguments()[0]; 
                Type groupElementType = this.ClrType.GetGenericArguments()[1]; 
                Type groupType = typeof(Grouping<,>).MakeGenericType(keyType, groupElementType);
                ConstructorInfo constructor = groupType.GetConstructors().Single(); 

                // new Grouping(children[0], children[1])
                Expression newGrouping = Expression.Convert(Expression.New(constructor, GetPropertyReaders(propertyTranslatorResults)), this.ClrType);
 
                return newGrouping;
            } 
 
            internal override IEnumerable GetChildTypes()
            { 
                // Collect information...
                Debug.Assert(ClrType.IsGenericType &&
                    typeof(IGrouping<,>).Equals(ClrType.GetGenericTypeDefinition()));
                Type keyType = this.ClrType.GetGenericArguments()[0]; 
                Type groupElementType = this.ClrType.GetGenericArguments()[1];
 
                // key 
                yield return keyType;
                // group 
                yield return typeof(IEnumerable<>).MakeGenericType(groupElementType);
            }
        }
 
        /// 
        /// Metadata for anonymous type materialization. 
        ///  
        private class ProjectionNewMetadata : InitializerMetadata
        { 
            internal ProjectionNewMetadata(NewExpression newExpression)
                : base(newExpression.Type)
            {
                Debug.Assert(null != newExpression); 
                _newExpression = newExpression;
            } 
 
            private readonly NewExpression _newExpression;
 
            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.ProjectionNew; } }

            protected override bool IsStructurallyEquivalent(InitializerMetadata other)
            { 
                // caller must ensure the type matches
                ProjectionNewMetadata otherProjection = (ProjectionNewMetadata)other; 
                if (this._newExpression.Members.Count != otherProjection._newExpression.Members.Count) 
                {
                    return false; 
                }

                for (int i = 0; i < this._newExpression.Members.Count; i++)
                { 
                    MemberInfo thisMember = this._newExpression.Members[i];
                    MemberInfo otherMember = otherProjection._newExpression.Members[i]; 
                    if (!thisMember.Equals(otherMember)) 
                    {
                        return false; 
                    }
                }

                return true; 
            }
 
            internal override Expression Emit(Translator translator, List propertyTranslatorResults) 
            {
                // Create expression of the form: 
                // _newExpression(children)

                // (ClrType)null
                Expression nullProjection = Expression.Constant(null, this.ClrType); 

                // _newExpression with members rebound 
                Expression newProjection = Expression.New(_newExpression.Constructor, GetPropertyReaders(propertyTranslatorResults)); 

                // _newExpression with members rebound to constants (used for security check) 
                Expression constantProjection = Expression.New(_newExpression.Constructor,
                    propertyTranslatorResults.Select(child => (Expression)Expression.Constant(TypeSystem.GetDefaultValue(child.Expression.Type), child.Expression.Type)));
                translator.RegisterUserExpression(constantProjection);
 
                // condition
                return newProjection; 
            } 

            internal override IEnumerable GetChildTypes() 
            {
                // return all argument types
                return _newExpression.Arguments.Select(arg => arg.Type);
            } 

            internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder) 
            { 
                base.AppendColumnMapKey(builder);
                builder.Append(_newExpression.Constructor.ToString()); 
                foreach (var member in _newExpression.Members ?? Enumerable.Empty())
                {
                    builder.Append("DT", member.DeclaringType);
                    builder.Append("." + member.Name); 
                }
            } 
        } 

        private class EmptyProjectionNewMetadata : ProjectionNewMetadata 
        {
            internal EmptyProjectionNewMetadata(NewExpression newExpression)
                : base(newExpression)
            { 
            }
            internal override Expression Emit(Translator translator, List propertyReaders) 
            { 
                // ignore sentinel column
                return base.Emit(translator, new List()); 
            }
            internal override IEnumerable GetChildTypes()
            {
                // ignore sentinel column 
                yield return null;
            } 
        } 

        ///  
        /// Metadata for standard projection initializers.
        /// 
        private class ProjectionInitializerMetadata : InitializerMetadata
        { 
            internal ProjectionInitializerMetadata(MemberInitExpression initExpression, MemberInfo[] members)
                : base(initExpression.Type) 
            { 
                Debug.Assert(null != initExpression);
                Debug.Assert(null != members); 
                _initExpression = initExpression;
                _members = members;
            }
 
            private readonly MemberInitExpression _initExpression;
            private readonly MemberInfo[] _members; 
 
            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.ProjectionInitializer; } }
 
            protected override bool IsStructurallyEquivalent(InitializerMetadata other)
            {
                // caller must ensure the type matches
                ProjectionInitializerMetadata otherProjection = (ProjectionInitializerMetadata)other; 
                if (this._initExpression.Bindings.Count != otherProjection._initExpression.Bindings.Count)
                { 
                    return false; 
                }
 
                for (int i = 0; i < this._initExpression.Bindings.Count; i++)
                {
                    MemberBinding thisBinding = this._initExpression.Bindings[i];
                    MemberBinding otherBinding = otherProjection._initExpression.Bindings[i]; 
                    if (!thisBinding.Member.Equals(otherBinding.Member))
                    { 
                        return false; 
                    }
                } 

                return true;
            }
 
            internal override Expression Emit(Translator translator, List propertyReaders)
            { 
                // Create expression of the form: 
                // _initExpression(children)
 
                // create member bindings (where values are taken from children)
                MemberBinding[] memberBindings = new MemberBinding[_initExpression.Bindings.Count];
                MemberBinding[] constantMemberBindings = new MemberBinding[memberBindings.Length];
                for (int i = 0; i < memberBindings.Length; i++) 
                {
                    MemberBinding originalBinding = _initExpression.Bindings[i]; 
                    Expression value = propertyReaders[i].Expression; 
                    MemberBinding newBinding = Expression.Bind(originalBinding.Member, value);
                    MemberBinding constantBinding = Expression.Bind(originalBinding.Member, Expression.Constant( 
                        TypeSystem.GetDefaultValue(value.Type), value.Type));
                    memberBindings[i] = newBinding;
                    constantMemberBindings[i] = constantBinding;
                } 

                Expression newProjection = Expression.MemberInit(_initExpression.NewExpression, memberBindings); 
                Expression constantProjection = Expression.MemberInit(_initExpression.NewExpression, constantMemberBindings); 

                translator.RegisterUserExpression(constantProjection); 

                return newProjection;
            }
 
            internal override IEnumerable GetChildTypes()
            { 
                // return all argument types 
                foreach (var binding in _initExpression.Bindings)
                { 
                    // determine member type
                    Type memberType;
                    string name;
                    TypeSystem.PropertyOrField(binding.Member, out name, out memberType); 
                    yield return memberType;
                } 
            } 

            internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder) 
            {
                base.AppendColumnMapKey(builder);
                foreach (var binding in _initExpression.Bindings)
                { 
                    builder.Append(",", binding.Member.DeclaringType);
                    builder.Append("." + binding.Member.Name); 
                } 
            }
        } 

        /// 
        /// Metadata for entity collection initializer.
        ///  
        private class EntityCollectionInitializerMetadata : InitializerMetadata
        { 
            internal EntityCollectionInitializerMetadata(Type type, NavigationProperty navigationProperty) 
                : base(type)
            { 
                Debug.Assert(null != navigationProperty);
                _navigationProperty = navigationProperty;
            }
 
            private readonly NavigationProperty _navigationProperty;
 
            internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.EntityCollection; } } 

            ///  
            /// Make sure the other metadata instance generates the same property
            /// (otherwise, we get incorrect behavior where multiple nav props return
            /// the same type)
            ///  
            protected override bool IsStructurallyEquivalent(InitializerMetadata other)
            { 
                // caller must ensure the type matches 
                EntityCollectionInitializerMetadata otherInitializer = (EntityCollectionInitializerMetadata)other;
                return this._navigationProperty.Equals(otherInitializer._navigationProperty); 
            }

            private static readonly MethodInfo s_createEntityCollectionMethod = typeof(EntityCollectionInitializerMetadata).GetMethod("CreateEntityCollection",
                BindingFlags.Static | BindingFlags.Public); 

            internal override Expression Emit(Translator translator, List propertyTranslatorResults) 
            { 
                Debug.Assert(propertyTranslatorResults.Count > 1, "no properties?");
                Debug.Assert(propertyTranslatorResults[1] is CollectionTranslatorResult, "not a collection?"); 

                Type elementType = GetElementType();
                MethodInfo createEntityCollectionMethod = s_createEntityCollectionMethod.MakeGenericMethod(elementType);
 
                Expression shaper = Translator.Shaper_Parameter;
                Expression owner = propertyTranslatorResults[0].Expression; 
 
                CollectionTranslatorResult collectionResult = propertyTranslatorResults[1] as CollectionTranslatorResult;
 
                Expression coordinator = collectionResult.ExpressionToGetCoordinator;

                // CreateEntityCollection(shaper, owner, elements, relationshipName, targetRoleName)
                Expression result = Expression.Call(createEntityCollectionMethod, 
                    shaper, owner, coordinator, Expression.Constant(_navigationProperty.RelationshipType.FullName), Expression.Constant(_navigationProperty.ToEndMember.Name));
 
                return result; 
            }
 
            public static EntityCollection CreateEntityCollection(Shaper state, IEntityWithRelationships owner, Coordinator coordinator, string relationshipName, string targetRoleName)
                where T : class, IEntityWithRelationships
            {
                if (null == owner) 
                {
                    return null; 
                } 
                else
                { 
                    EntityCollection result = owner.RelationshipManager.GetRelatedCollection(relationshipName, targetRoleName);
                    // register a handler for deferred loading (when the nested result has been consumed)
                    coordinator.RegisterCloseHandler((readerState, elements) => result.Load(elements, readerState.MergeOption));
                    return result; 
                }
            } 
 
            internal override IEnumerable GetChildTypes()
            { 
                Type elementType = GetElementType();
                yield return null; // defer in determining entity type...
                yield return typeof(IEnumerable<>).MakeGenericType(elementType);
            } 

 
            internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder) 
            {
                base.AppendColumnMapKey(builder); 
                builder.Append(",NP" + _navigationProperty.Name);
                builder.Append(",AT", _navigationProperty.DeclaringType);
            }
 
            private Type GetElementType()
            { 
                if (!this.ClrType.IsGenericType || !typeof(EntityCollection<>).Equals(ClrType.GetGenericTypeDefinition())) 
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnexpectedTypeForNavigationProperty( 
                        _navigationProperty,
                        typeof(EntityCollection<>),
                        ClrType));
                } 
                Type elementType = this.ClrType.GetGenericArguments()[0];
                return elementType; 
            } 
        }
 
    }

    internal enum InitializerMetadataKind
    { 
        Grouping,
        ProjectionNew, 
        ProjectionInitializer, 
        EntityCollection,
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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