Translator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / Translator.cs / 1305376 / Translator.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System.Data.Common.CommandTrees;
using System.Collections.Generic; 
using System.Diagnostics;
using System.Data.Metadata.Edm;
using System.Linq.Expressions;
using System.Reflection; 
using System.Data.Objects.DataClasses;
using System.Globalization; 
using System.Data.Entity; 
using System.Data.Common.CommandTrees.ExpressionBuilder;
using System.Linq; 
namespace System.Data.Objects.ELinq
{
    internal sealed partial class ExpressionConverter
    { 
        // Base class supporting the translation of LINQ node type(s) given a LINQ expression
        // of that type, and the "parent" translation context (the ExpressionConverter processor) 
        private abstract class Translator 
        {
            private readonly ExpressionType[] _nodeTypes; 
            protected Translator(params ExpressionType[] nodeTypes)
            {
                _nodeTypes = nodeTypes;
            } 
            // Gets LINQ node types this translator should be registed to process.
            internal IEnumerable NodeTypes { get { return _nodeTypes; } } 
            internal abstract DbExpression Translate(ExpressionConverter parent, Expression linq); 
            public override string ToString()
            { 
                return this.GetType().Name;
            }
        }
 
        #region Misc
        // Typed version of Translator 
        private abstract class TypedTranslator : Translator 
            where T_Linq : Expression
        { 
            protected TypedTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { }
            internal override DbExpression Translate(ExpressionConverter parent, Expression linq)
            { 
                return TypedTranslate(parent, (T_Linq)linq);
            } 
            protected abstract DbExpression TypedTranslate(ExpressionConverter parent, T_Linq linq); 
        }
        private sealed class ConstantTranslator 
            : TypedTranslator
        {
            internal ConstantTranslator()
                : base(ExpressionType.Constant) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
            { 
                // Check to see if this constant corresponds to the compiled query context parameter (it 
                // gets turned into a constant during funcletization and has special error handling).
                if (linq == parent._funcletizer.RootContextExpression) 
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnsupportedUseOfContextParameter(
                        parent._funcletizer.RootContextParameter.Name));
                } 

                ObjectQuery queryOfT = linq.Value as ObjectQuery; 
                if (null != queryOfT) 
                {
                    return parent.TranslateInlineQueryOfT(queryOfT); 
                }

                // If it is something we can enumerate then we can evaluate locally and send to the server
                var values = linq.Value as System.Collections.IEnumerable; 
                if (values != null)
                { 
                    Type elementType = TypeSystem.GetElementType(linq.Type); 
                    if ((elementType != null) && (elementType != linq.Type))
                    { 
                        var expressions = new List();
                        foreach (object o in values)
                        {
                            expressions.Add(Expression.Constant(o, elementType)); 
                        }
 
                        // Invalidate the query plan every time the query is executed since it is possible 
                        // to modify an element of a collection without changing the reference.
                        parent._recompileRequired = () => true; 

                        return parent.TranslateExpression(Expression.NewArrayInit(elementType, expressions));
                    }
                } 

                bool isNullValue = null == linq.Value; 
 
                // Remove facet information: null instances do not constrain type facets (e.g. a null string does not restrict
                // "length" in compatibility checks) 
                TypeUsage type;
                bool typeSupported = false;
                if (parent.TryGetValueLayerType(linq.Type, out type))
                { 
                    // For constant values, support only primitive type (this is all that is supported by CQTs)
                    // For null types, also allow EntityType. Although other types claim to be supported, they 
                    // don't work (e.g. complex type, see SQL BU 543956) 
                    if (type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType ||
                        (isNullValue && type.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)) 
                    {
                        typeSupported = true;
                    }
                } 

                if (!typeSupported) 
                { 
                    throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedConstant(DescribeClrType(linq.Type), Strings.ELinq_PrimitiveTypesSample));
                } 

                // create a constant or null expression depending on value
                if (isNullValue)
                { 
                    return DbExpressionBuilder.Null(type);
                } 
                else 
                {
                    return DbExpressionBuilder.Constant(type, linq.Value); 
                }
            }
        }
        private sealed class MemberAccessTranslator 
            : TypedTranslator
        { 
            internal MemberAccessTranslator() 
                : base(ExpressionType.MemberAccess) { }
            // attempt to translate the member access to a "regular" property, a navigation property, or a calculated 
            // property
            protected override DbExpression TypedTranslate(ExpressionConverter parent, MemberExpression linq)
            {
                DbExpression propertyExpression; 
                string memberName;
                Type memberType; 
                MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Member, out memberName, out memberType); 

                // note: we check for "regular" properties last, since the other two flavors derive 
                // from this one
                if (linq.Expression != null)
                {
                    DbExpression instance = parent.TranslateExpression(linq.Expression); 
                    if (TryResolveAsProperty(parent, memberInfo,
                        instance.ResultType, instance, out propertyExpression)) 
                    { 
                        return propertyExpression;
                    } 
                }

                if (memberInfo.MemberType == MemberTypes.Property)
                { 
                    // Check whether it is one of the special properties that we know how to translate
                    PropertyTranslator propertyTranslator; 
                    if (TryGetTranslator((PropertyInfo)memberInfo, out propertyTranslator)) 
                    {
                        return propertyTranslator.Translate(parent, linq); 
                    }
                }

                // no other property types are supported by LINQ over entities 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnrecognizedMember(linq.Member.Name));
            } 
 
            #region Static members and initializers
            private static readonly Dictionary s_propertyTranslators; 
            private static bool s_vbPropertiesInitialized;
            private static readonly object s_vbInitializerLock = new object();

            static MemberAccessTranslator() 
            {
                // initialize translators for specific properties 
                s_propertyTranslators = new Dictionary(); 
                foreach (PropertyTranslator translator in GetPropertyTranslators())
                { 
                    foreach (PropertyInfo property in translator.Properties)
                    {
                        s_propertyTranslators.Add(property, translator);
                    } 
                }
            } 
 
            /// 
            /// Tries to get a translator for the given property info. 
            /// If the given property info corresponds to a Visual Basic property,
            /// it also initializes the Visual Basic translators if they have not been initialized
            /// 
            ///  
            /// 
            ///  
            private static bool TryGetTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator) 
            {
                //If the type is generic, we try to match the generic property 
                PropertyInfo nonGenericPropertyInfo = propertyInfo;
                if (propertyInfo.DeclaringType.IsGenericType)
                {
                    try 
                    {
                        propertyInfo = propertyInfo.DeclaringType.GetGenericTypeDefinition().GetProperty(propertyInfo.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); 
                    } 
                    catch (AmbiguousMatchException)
                    { 
                        propertyTranslator = null;
                        return false;
                    }
                    if (propertyInfo == null) 
                    {
                        propertyTranslator = null; 
                        return false; 
                    }
                } 

                PropertyTranslator translatorInstance;
                if (s_propertyTranslators.TryGetValue(propertyInfo, out translatorInstance))
                { 
                    propertyTranslator = translatorInstance;
                    return true; 
                } 

                // check if this is the visual basic assembly 
                if (s_visualBasicAssemblyFullName == propertyInfo.DeclaringType.Assembly.FullName)
                {
                    lock (s_vbInitializerLock)
                    { 
                        if (!s_vbPropertiesInitialized)
                        { 
                            InitializeVBProperties(propertyInfo.DeclaringType.Assembly); 
                            s_vbPropertiesInitialized = true;
                        } 
                        // try again
                        if (s_propertyTranslators.TryGetValue(propertyInfo, out translatorInstance))
                        {
                            propertyTranslator = translatorInstance; 
                            return true;
                        } 
                        else 
                        {
                            propertyTranslator = null; 
                            return false;
                        }
                    }
                } 

                if (GenericICollectionTranslator.TryGetPropertyTranslator(nonGenericPropertyInfo, out propertyTranslator)) 
                { 
                    return true;
                } 

                propertyTranslator = null;
                return false;
            } 

            // Determines if the given property can be resolved as a standard or navigation property. 
            private static bool TryResolveAsProperty(ExpressionConverter parent, 
                MemberInfo clrMember, TypeUsage definingType, DbExpression instance, out DbExpression propertyExpression)
            { 
                // retrieve members directly from row types, which are not mapped between O and C
                RowType rowType = definingType.EdmType as RowType;
                string name = clrMember.Name;
 
                if (null != rowType)
                { 
                    EdmMember member; 
                    if (rowType.Members.TryGetValue(name, false, out member))
                    { 
                        propertyExpression = instance.Property(name);
                        return true;
                    }
 
                    propertyExpression = null;
                    return false; 
                } 

                // for non-row structural types, map from the O to the C layer using the perspective 
                StructuralType structuralType = definingType.EdmType as StructuralType;
                if (null != structuralType)
                {
                    EdmMember member = null; 
                    if (parent._perspective.TryGetMember(structuralType, name, false, out member))
                    { 
                        if (null != member) 
                        {
                            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty) 
                            {
                                NavigationProperty navProp = (NavigationProperty)member;
                                propertyExpression = TranslateNavigationProperty(parent, clrMember, instance, navProp);
                                return true; 
                            }
                            else 
                            { 
                                propertyExpression = instance.Property(name);
                                return true; 
                            }

                        }
                    } 
                }
 
                // try to unwrap GroupBy "Key" member 
                if (name == ExpressionConverter.KeyColumnName)
                { 
                    // see if we can "unwrap" the current instance
                    if (DbExpressionKind.Property == instance.ExpressionKind)
                    {
                        DbPropertyExpression property = (DbPropertyExpression)instance; 
                        InitializerMetadata initializerMetadata;
 
                        // if we're dealing with the "Group" property of a GroupBy projection, we know how to unwrap 
                        // it
                        if (property.Property.Name == ExpressionConverter.GroupColumnName && // only know how to unwrap the group 
                            InitializerMetadata.TryGetInitializerMetadata(property.Instance.ResultType, out initializerMetadata) &&
                            initializerMetadata.Kind == InitializerMetadataKind.Grouping)
                        {
                            propertyExpression = property.Instance.Property(ExpressionConverter.KeyColumnName); 
                            return true;
                        } 
                    } 
                }
 
                propertyExpression = null;
                return false;
            }
 
            private static DbExpression TranslateNavigationProperty(ExpressionConverter parent, MemberInfo clrMember, DbExpression instance, NavigationProperty navProp)
            { 
                DbExpression propertyExpression; 
                propertyExpression = instance.Property(navProp);
 
                // for EntityCollection navigations, wrap in "grouping" where the key is the parent
                // entity and the group contains the child entities
                // For non-EntityCollection navigations (e.g. from POCO entities), we just need the
                // enumeration, not the grouping 
                if (BuiltInTypeKind.CollectionType == propertyExpression.ResultType.EdmType.BuiltInTypeKind)
                { 
                    Debug.Assert(clrMember is PropertyInfo, "Navigation property was not a property; should not be allowed by metadata."); 
                    Type propertyType = ((PropertyInfo)clrMember).PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>)) 
                    {
                        List> collectionColumns =
                            new List>(2);
                        collectionColumns.Add(new KeyValuePair( 
                            ExpressionConverter.EntityCollectionOwnerColumnName, instance));
                        collectionColumns.Add(new KeyValuePair( 
                            ExpressionConverter.EntityCollectionElementsColumnName, propertyExpression)); 
                        propertyExpression = parent.CreateNewRowExpression(collectionColumns,
                            InitializerMetadata.CreateEntityCollectionInitializer(parent.EdmItemCollection, ((PropertyInfo)clrMember).PropertyType, navProp)); 
                    }
                }
                return propertyExpression;
            } 

            private static DbExpression TranslateCount(ExpressionConverter parent, Type sequenceElementType, Expression sequence) 
            { 
                // retranslate as a Count() aggregate, since the name collision prevents us
                // from calling the method directly in VB and C# 
                MethodInfo countMethod;
                ReflectionUtil.TryLookupMethod(SequenceMethod.Count, out countMethod);
                Debug.Assert(null != countMethod, "Count() must exist");
                countMethod = countMethod.MakeGenericMethod(sequenceElementType); 
                Expression countCall = Expression.Call(countMethod, sequence);
                return parent.TranslateExpression(countCall); 
            } 

            private static void InitializeVBProperties(Assembly vbAssembly) 
            {
                Debug.Assert(!s_vbPropertiesInitialized);
                foreach (PropertyTranslator translator in GetVisualBasicPropertyTranslators(vbAssembly))
                { 
                    foreach (PropertyInfo property in translator.Properties)
                    { 
                        s_propertyTranslators.Add(property, translator); 
                    }
                } 
            }

            private static IEnumerable GetVisualBasicPropertyTranslators(Assembly vbAssembly)
            { 
                yield return new VBDateAndTimeNowTranslator(vbAssembly);
            } 
 
            private static IEnumerable GetPropertyTranslators()
            { 
                yield return new DefaultCanonicalFunctionPropertyTranslator();
                yield return new RenameCanonicalFunctionPropertyTranslator();
                yield return new EntityCollectionCountTranslator();
                yield return new NullableHasValueTranslator(); 
                yield return new NullableValueTranslator();
            } 
 
            /// 
            /// This method is used to determine whether client side evaluation should be done, 
            /// if the property can be evaluated in the store, it is not being evaluated on the client
            /// 
            internal static bool CanFuncletizePropertyInfo(PropertyInfo propertyInfo)
            { 
                PropertyTranslator propertyTranslator;
                // In most cases, we only allow funcletization of properties that could not otherwise be 
                // handled by the query pipeline. ICollection<>.Count is the one exception to the rule 
                // (avoiding a breaking change)
                return GenericICollectionTranslator.TryGetPropertyTranslator(propertyInfo, out propertyTranslator) || 
                    !TryGetTranslator(propertyInfo, out propertyTranslator);
            }
            #endregion
 
            #region Dynamic Property Translators
 
            private sealed class GenericICollectionTranslator : PropertyTranslator 
            {
                private readonly Type _elementType; 

                private GenericICollectionTranslator(Type elementType) : base(Enumerable.Empty())
                {
                    _elementType = elementType; 
                }
 
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    return TranslateCount(parent, _elementType, call.Expression); 
                }

                internal static bool TryGetPropertyTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator)
                { 
                    // Implementation note: When adding support for additional properties, use less expensive checks
                    // such as property name and return type to test for a property defined by ICollection first 
                    // before calling the more expensive TypeSystem.FindICollection to test whether the declaring type 
                    // of the property implements ICollection.
 
                    //
                    // Int32 Count
                    //
                    if (propertyInfo.Name == "Count" && 
                        propertyInfo.PropertyType.Equals(typeof(int)))
                    { 
                        foreach (KeyValuePair implementedCollectionInfo in GetImplementedICollections(propertyInfo.DeclaringType)) 
                        {
                            Type implementedCollection = implementedCollectionInfo.Key; 
                            Type elementType = implementedCollectionInfo.Value;

                            if (propertyInfo.IsImplementationOf(implementedCollection))
                            { 
                                propertyTranslator = new GenericICollectionTranslator(elementType);
                                return true; 
                            } 
                        }
                    } 

                    // Not a supported ICollection property
                    propertyTranslator = null;
                    return false; 
                }
 
                private static bool IsICollection(Type candidateType, out Type elementType) 
                {
                    if (candidateType.IsGenericType && 
                        candidateType.GetGenericTypeDefinition().Equals(typeof(System.Collections.Generic.ICollection<>)))
                    {
                        elementType = candidateType.GetGenericArguments()[0];
                        return true; 
                    }
                    elementType = null; 
                    return false; 
                }
 
                private static IEnumerable> GetImplementedICollections(Type type)
                {
                    Type collectionElementType;
                    if (IsICollection(type, out collectionElementType)) 
                    {
                        yield return new KeyValuePair(type, collectionElementType); 
                    } 
                    else
                    { 
                        foreach (Type interfaceType in type.GetInterfaces())
                        {
                            if (IsICollection(interfaceType, out collectionElementType))
                            { 
                                yield return new KeyValuePair(interfaceType, collectionElementType);
                            } 
                        } 
                    }
                } 
            }

            #endregion
 
            #region Signature-based Property Translators
            private abstract class PropertyTranslator 
            { 
                private readonly IEnumerable _properties;
                protected PropertyTranslator(params PropertyInfo[] properties) { _properties = properties; } 
                protected PropertyTranslator(IEnumerable properties) { _properties = properties; }
                internal IEnumerable Properties { get { return _properties; } }
                internal abstract DbExpression Translate(ExpressionConverter parent, MemberExpression call);
                public override string ToString() 
                {
                    return GetType().Name; 
                } 
            }
 
            private sealed class DefaultCanonicalFunctionPropertyTranslator : PropertyTranslator
            {
                internal DefaultCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties() 
                { 
                    yield return typeof(String).GetProperty("Length", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance); 
 
                    yield return typeof(DateTimeOffset).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);
                } 
 
                // Default translator for method calls into canonical functions.
                // Translation: 
                //      object.PropertyName  -> PropertyName(object)
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
                {
                    return parent.TranslateIntoCanonicalFunction(call.Member.Name, call, call.Expression); 
                }
            } 
 
            private sealed class RenameCanonicalFunctionPropertyTranslator : PropertyTranslator
            { 
                private static readonly Dictionary s_propertyRenameMap = new Dictionary(2);

                internal RenameCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties() 
                { 
                    yield return GetProperty(typeof(DateTime), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTime);
                    yield return GetProperty(typeof(DateTime), "UtcNow", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentUtcDateTime); 
                    yield return GetProperty(typeof(DateTimeOffset), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTimeOffset);

                    yield return GetProperty(typeof(TimeSpan), "Hours", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Hour);
                    yield return GetProperty(typeof(TimeSpan), "Minutes", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Minute); 
                    yield return GetProperty(typeof(TimeSpan), "Seconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Second);
                    yield return GetProperty(typeof(TimeSpan), "Milliseconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Millisecond); 
                } 

                private static PropertyInfo GetProperty(Type declaringType, string propertyName, BindingFlags bindingFlages, string canonicalFunctionName) 
                {
                    PropertyInfo propertyInfo = declaringType.GetProperty(propertyName, bindingFlages);
                    s_propertyRenameMap.Add(propertyInfo, canonicalFunctionName);
                    return propertyInfo; 
                }
 
                // Translator for static properties into canonical functions when there is a corresponding 
                // canonical function but with a differnet name
                // Translation: 
                //      object.PropertyName  -> CanonicalFunctionName(object)
                //      Type.PropertyName  -> CanonicalFunctionName()
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    PropertyInfo property = (PropertyInfo)call.Member;
                    String canonicalFunctionName = s_propertyRenameMap[property]; 
                    DbExpression result; 
                    if (call.Expression == null)
                    { 
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call);
                    }
                    else
                    { 
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call, call.Expression);
                    } 
                    return result; 
                }
            } 

            private sealed class VBDateAndTimeNowTranslator : PropertyTranslator
            {
                private const string s_dateAndTimeTypeFullName = "Microsoft.VisualBasic.DateAndTime"; 

                internal VBDateAndTimeNowTranslator(Assembly vbAssembly) 
                    : base(GetProperty(vbAssembly)) { } 

                private static PropertyInfo GetProperty(Assembly vbAssembly) 
                {
                    return vbAssembly.GetType(s_dateAndTimeTypeFullName).GetProperty("Now", BindingFlags.Public | BindingFlags.Static);
                }
 
                // Translation:
                //      Now -> GetDate() 
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    return parent.TranslateIntoCanonicalFunction(ExpressionConverter.CurrentDateTime, call); 
                }
            }

            private sealed class EntityCollectionCountTranslator : PropertyTranslator 
            {
                internal EntityCollectionCountTranslator() 
                    : base(GetProperty()) { } 

                private static PropertyInfo GetProperty() 
                {
                    return typeof(EntityCollection<>).GetProperty(ExpressionConverter.s_entityCollectionCountPropertyName, BindingFlags.Public | BindingFlags.Instance);
                }
 
                // Translation:
                //      EntityCollection.Count -> Count() 
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    // retranslate as a Count() aggregate, since the name collision prevents us 
                    // from calling the method directly in VB and C#
                    return MemberAccessTranslator.TranslateCount(parent, call.Member.DeclaringType.GetGenericArguments()[0], call.Expression);
                }
            } 

            private sealed class NullableHasValueTranslator : PropertyTranslator 
            { 
                internal NullableHasValueTranslator()
                    : base(GetProperty()) { } 

                private static PropertyInfo GetProperty()
                {
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableHasValuePropertyName, BindingFlags.Public | BindingFlags.Instance); 
                }
 
                // Translation: 
                //      Nullable.HasValue -> Not(IsNull(arg))
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    DbExpression argument = parent.TranslateExpression(call.Expression);
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type");
                    return parent.CreateIsNullExpression(argument, call.Expression.Type).Not(); 
                }
            } 
 
            private sealed class NullableValueTranslator : PropertyTranslator
            { 
                internal NullableValueTranslator()
                    : base(GetProperty()) { }

                private static PropertyInfo GetProperty() 
                {
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableValuePropertyName, BindingFlags.Public | BindingFlags.Instance); 
                } 

                // Translation: 
                //      Nullable.Value -> arg
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
                {
                    DbExpression argument = parent.TranslateExpression(call.Expression); 
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type");
                    return argument; 
                } 
            }
            #endregion 
        }
        private sealed class ParameterTranslator
            : TypedTranslator
        { 
            internal ParameterTranslator()
                : base(ExpressionType.Parameter) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ParameterExpression linq) 
            {
                // Bindings should be intercepted before we get to this point (in ExpressionConverter.TranslateExpression) 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnboundParameterExpression(linq.Name));
            }
        }
        private sealed class NewTranslator 
            : TypedTranslator
        { 
            internal NewTranslator() 
                : base(ExpressionType.New) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, NewExpression linq) 
            {
                int memberCount = null == linq.Members ? 0 : linq.Members.Count;

                if (null == linq.Constructor || 
                    linq.Arguments.Count != memberCount)
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor); 
                }
 
                parent.CheckInitializerType(linq.Type);

                List> recordColumns =
                    new List>(memberCount + 1); 

                HashSet memberNames = new HashSet(StringComparer.Ordinal); 
                for (int i = 0; i < memberCount; i++) 
                {
                    string memberName; 
                    Type memberType;
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Members[i], out memberName, out memberType);
                    DbExpression memberValue = parent.TranslateExpression(linq.Arguments[i]);
                    memberNames.Add(memberName); 
                    recordColumns.Add(new KeyValuePair(memberName, memberValue));
                } 
 
                InitializerMetadata initializerMetadata;
                if (0 == memberCount) 
                {
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(DbExpressionBuilder.True.As(KeyColumnName));
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq); 
                }
                else 
                { 
                    // Construct a new initializer type in metadata for this projection (provides the
                    // necessary context for the object materializer) 
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq);
                }
                parent.ValidateInitializerMetadata(initializerMetadata);
 
                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata);
 
                return projection; 
            }
        } 
        private sealed class NewArrayInitTranslator
            : TypedTranslator
        {
            internal NewArrayInitTranslator() 
                : base(ExpressionType.NewArrayInit) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, NewArrayExpression linq) 
            { 
                if (linq.Expressions.Count > 0)
                { 
                    return DbExpressionBuilder.NewCollection(linq.Expressions.Select(e => parent.TranslateExpression(e)));
                }

                TypeUsage typeUsage; 
                if (parent.TryGetValueLayerType(linq.Type, out typeUsage))
                { 
                    return DbExpressionBuilder.NewEmptyCollection(typeUsage); 
                }
 
                throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedType(DescribeClrType(linq.Type)));
            }
        }
        private sealed class ListInitTranslator 
            : TypedTranslator
        { 
            internal ListInitTranslator() 
                : base(ExpressionType.ListInit ) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ListInitExpression linq) 
            {
                // Ensure requirements: one list initializer argument and a default constructor.
                if ((linq.NewExpression.Constructor != null) && (linq.NewExpression.Constructor.GetParameters().Length != 0))
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
                } 
 
                if (linq.Initializers.Any(i => i.Arguments.Count != 1))
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedInitializers);
                }

                return DbExpressionBuilder.NewCollection(linq.Initializers.Select(i => parent.TranslateExpression(i.Arguments[0]))); 
            }
        } 
        private sealed class MemberInitTranslator 
            : TypedTranslator
        { 
            internal MemberInitTranslator()
                : base(ExpressionType.MemberInit) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)
            { 
                if (null == linq.NewExpression.Constructor ||
                    0 != linq.NewExpression.Constructor.GetParameters().Length) 
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
                } 

                parent.CheckInitializerType(linq.Type);

                List> recordColumns = 
                    new List>(linq.Bindings.Count + 1);
                MemberInfo[] members = new MemberInfo[linq.Bindings.Count]; 
 
                HashSet memberNames = new HashSet(StringComparer.Ordinal);
                for (int i = 0; i < linq.Bindings.Count; i++) 
                {
                    MemberAssignment binding = linq.Bindings[i] as MemberAssignment;
                    if (null == binding)
                    { 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedBinding);
                    } 
                    string memberName; 
                    Type memberType;
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(binding.Member, out memberName, out memberType); 

                    DbExpression memberValue = parent.TranslateExpression(binding.Expression);
                    memberNames.Add(memberName);
                    members[i] = memberInfo; 
                    recordColumns.Add(new KeyValuePair(memberName, memberValue));
                } 
 
                InitializerMetadata initializerMetadata;
 
                if (0 == recordColumns.Count)
                {
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(DbExpressionBuilder.Constant(true).As(KeyColumnName)); 
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq.NewExpression);
                } 
                else 
                {
                    // Construct a new initializer type in metadata for this projection (provides the 
                    // necessary context for the object materializer)
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq, members);
                }
                parent.ValidateInitializerMetadata(initializerMetadata); 
                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata);
 
                return projection; 
            }
        } 
        private sealed class ConditionalTranslator : TypedTranslator
        {
            internal ConditionalTranslator()
                : base(ExpressionType.Conditional) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ConditionalExpression linq)
            { 
                // translate Test ? IfTrue : IfFalse --> CASE WHEN Test THEN IfTrue ELSE IfFalse 
                List whenExpressions = new List(1);
                whenExpressions.Add(parent.TranslateExpression(linq.Test)); 
                List thenExpressions = new List(1);
                thenExpressions.Add(parent.TranslateExpression(linq.IfTrue));
                DbExpression elseExpression = parent.TranslateExpression(linq.IfFalse);
                return DbExpressionBuilder.Case(whenExpressions, thenExpressions, elseExpression); 
            }
        } 
        private sealed class NotSupportedTranslator : Translator 
        {
            internal NotSupportedTranslator(params ExpressionType[] nodeTypes) 
                : base(nodeTypes)
            {
            }
            internal override DbExpression Translate(ExpressionConverter parent, Expression linq) 
            {
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType)); 
            } 
        }
        private sealed class ExtensionTranslator : Translator 
        {
            internal ExtensionTranslator()
                : base(EntityExpressionVisitor.CustomExpression)
            { 
            }
            internal override DbExpression Translate(ExpressionConverter parent, Expression linq) 
            { 
                QueryParameterExpression queryParameter = linq as QueryParameterExpression;
                if (null == queryParameter) 
                {
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType));
                }
                // otherwise add a new query parameter... 
                parent.AddParameter(queryParameter);
                return queryParameter.ParameterReference; 
            } 
        }
        #endregion 

        #region Binary expression translators
        private abstract class BinaryTranslator
            : TypedTranslator 
        {
            protected BinaryTranslator(params ExpressionType[] nodeTypes) 
                : base(nodeTypes) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            { 
                return TranslateBinary(parent, parent.TranslateExpression(linq.Left), parent.TranslateExpression(linq.Right), linq);
            }
            protected abstract DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq);
        } 
        private sealed class CoalesceTranslator : BinaryTranslator
        { 
            internal CoalesceTranslator() 
                : base(ExpressionType.Coalesce) { }
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq) 
            {
                // left ?? right gets translated to:
                // CASE WHEN IsNull(left) THEN right ELSE left
 
                // construct IsNull
                DbExpression isNull = parent.CreateIsNullExpression(left, linq.Left.Type); 
 
                // construct case expression
                List whenExpressions = new List(1); 
                whenExpressions.Add(isNull);
                List thenExpressions = new List(1);
                thenExpressions.Add(right);
                DbExpression caseExpression = DbExpressionBuilder.Case(whenExpressions, 
                    thenExpressions, left);
 
                return caseExpression; 
            }
        } 
        private sealed class AndAlsoTranslator : BinaryTranslator
        {
            internal AndAlsoTranslator()
                : base(ExpressionType.AndAlso) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.And(right); 
            }
        } 
        private sealed class OrElseTranslator : BinaryTranslator
        {
            internal OrElseTranslator()
                : base(ExpressionType.OrElse) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Or(right); 
            }
        } 
        private sealed class LessThanTranslator : BinaryTranslator
        {
            internal LessThanTranslator()
                : base(ExpressionType.LessThan) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.LessThan(right); 
            }
        } 
        private sealed class LessThanOrEqualsTranslator : BinaryTranslator
        {
            internal LessThanOrEqualsTranslator()
                : base(ExpressionType.LessThanOrEqual) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.LessThanOrEqual(right); 
            }
        } 
        private sealed class GreaterThanTranslator : BinaryTranslator
        {
            internal GreaterThanTranslator()
                : base(ExpressionType.GreaterThan) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.GreaterThan(right); 
            }
        } 
        private sealed class GreaterThanOrEqualsTranslator : BinaryTranslator
        {
            internal GreaterThanOrEqualsTranslator()
                : base(ExpressionType.GreaterThanOrEqual) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.GreaterThanOrEqual(right); 
            }
        } 
        private sealed class EqualsTranslator : TypedTranslator
        {
            internal EqualsTranslator()
                : base(ExpressionType.Equal) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            { 
                Expression linqLeft = linq.Left; 
                Expression linqRight = linq.Right;
 
                bool leftIsNull = ExpressionIsNullConstant(linqLeft);
                bool rightIsNull = ExpressionIsNullConstant(linqRight);

                // if both values are null, short-circuit 
                if (leftIsNull && rightIsNull) { return DbExpressionBuilder.True; }
 
                // if only one side is null, produce an IsNull statement 
                if (leftIsNull) { return CreateIsNullExpression(parent, linqRight); }
                if (rightIsNull) { return CreateIsNullExpression(parent, linqLeft); } 

                // create a standard equals expression, calling utility method to compensate for null equality
                DbExpression cqtLeft = parent.TranslateExpression(linqLeft);
                DbExpression cqtRight = parent.TranslateExpression(linqRight); 
                return parent.CreateEqualsExpression(cqtLeft, cqtRight, EqualsPattern.Store, linqLeft.Type, linqRight.Type);
            } 
            private static DbExpression CreateIsNullExpression(ExpressionConverter parent, Expression input) 
            {
                input = UnwrapConvert(input); 

                // translate input
                DbExpression inputCqt = parent.TranslateExpression(input);
 
                // create IsNull expression
                return parent.CreateIsNullExpression(inputCqt, input.Type); 
            } 
            private static bool ExpressionIsNullConstant(Expression expression)
            { 
                // convert statements introduced by compiler should not affect nullness
                expression = UnwrapConvert(expression);

                // check if the unwrapped expression is a null constant 
                if (ExpressionType.Constant != expression.NodeType) { return false; }
                System.Linq.Expressions.ConstantExpression constant = (System.Linq.Expressions.ConstantExpression)expression; 
                return null == constant.Value; 
            }
            private static Expression UnwrapConvert(Expression input) 
            {
                // unwrap all converts
                while (ExpressionType.Convert == input.NodeType)
                { 
                    input = ((UnaryExpression)input).Operand;
                } 
                return input; 
            }
        } 
        private sealed class NotEqualsTranslator : TypedTranslator
        {
            internal NotEqualsTranslator()
                : base(ExpressionType.NotEqual) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            { 
                // rewrite as a not equals expression 
                Expression notLinq = Expression.Not(
                    Expression.Equal(linq.Left, linq.Right)); 
                return parent.TranslateExpression(notLinq);
            }
        }
        #endregion 

        #region Type binary expression translator 
        private sealed class IsTranslator : TypedTranslator 
        {
            internal IsTranslator() 
                : base(ExpressionType.TypeIs) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, TypeBinaryExpression linq)
            {
                DbExpression operand = parent.TranslateExpression(linq.Expression); 
                TypeUsage fromType = operand.ResultType;
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeIs, linq.TypeOperand, linq.Expression.Type); 
                return operand.IsOf(toType); 
            }
        } 
        #endregion

        #region Arithmetic expressions
        private sealed class AddTranslator : BinaryTranslator 
        {
            internal AddTranslator() 
                : base(ExpressionType.Add, ExpressionType.AddChecked) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                if (TypeSemantics.IsPrimitiveType(left.ResultType, PrimitiveTypeKind.String) &&
                   TypeSemantics.IsPrimitiveType(right.ResultType, PrimitiveTypeKind.String))
                {
                    // Add(string, string) => Concat(string, string) 
                    return parent.CreateCanonicalFunction(ExpressionConverter.Concat, linq, left, right);
                } 
                else 
                {
                    return left.Plus(right); 
                }
            }
        }
        private sealed class DivideTranslator : BinaryTranslator 
        {
            internal DivideTranslator() 
                : base(ExpressionType.Divide) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Divide(right);
            }
        }
        private sealed class ModuloTranslator : BinaryTranslator 
        {
            internal ModuloTranslator() 
                : base(ExpressionType.Modulo) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Modulo(right);
            }
        }
        private sealed class MultiplyTranslator : BinaryTranslator 
        {
            internal MultiplyTranslator() 
                : base(ExpressionType.Multiply, ExpressionType.MultiplyChecked) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Multiply(right);
            }
        }
        private sealed class SubtractTranslator : BinaryTranslator 
        {
            internal SubtractTranslator() 
                : base(ExpressionType.Subtract, ExpressionType.SubtractChecked) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Minus(right);
            }
        }
        private sealed class NegateTranslator : UnaryTranslator 
        {
            internal NegateTranslator() 
                : base(ExpressionType.Negate, ExpressionType.NegateChecked) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
            { 
                return operand.UnaryMinus();
            }
        }
        private sealed class UnaryPlusTranslator : UnaryTranslator 
        {
            internal UnaryPlusTranslator() 
                : base(ExpressionType.UnaryPlus) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, UnaryExpression unary, DbExpression operand)
            { 
                // +x = x
                return operand;
            }
        } 
        #endregion
 
        #region Bitwise expressions 
        private abstract class BitwiseBinaryTranslator : TypedTranslator
        { 
            private readonly string _canonicalFunctionName;

            protected BitwiseBinaryTranslator(ExpressionType nodeType, string canonicalFunctionName)
                : base(nodeType) 
            {
                _canonicalFunctionName = canonicalFunctionName; 
            } 

            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq) 
            {
                DbExpression left = parent.TranslateExpression(linq.Left);
                DbExpression right = parent.TranslateExpression(linq.Right);
 
                //If the arguments are binary we translate into logic expressions
                if (TypeSemantics.IsBooleanType(left.ResultType)) 
                { 
                    return TranslateIntoLogicExpression(parent, linq, left, right);
                } 

                //Otherwise we translate into bitwise canonical functions
                return parent.CreateCanonicalFunction(_canonicalFunctionName, linq, left, right);
            } 
            protected abstract DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right);
        } 
        private sealed class AndTranslator : BitwiseBinaryTranslator 
        {
            internal AndTranslator() 
                : base(ExpressionType.And, ExpressionConverter.BitwiseAnd) { }
            protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
            {
                return left.And(right); 
            }
        } 
        private sealed class OrTranslator : BitwiseBinaryTranslator 
        {
            internal OrTranslator() 
                : base(ExpressionType.Or, ExpressionConverter.BitwiseOr) { }
            protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
            {
                return left.Or(right); 
            }
        } 
        private sealed class ExclusiveOrTranslator : BitwiseBinaryTranslator 
        {
            internal ExclusiveOrTranslator() 
                : base(ExpressionType.ExclusiveOr, ExpressionConverter.BitwiseXor) { }
            protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
            {
                //No direct translation, we translate into ((left && !right) || (!left && right)) 
                DbExpression firstExpression = left.And(right.Not());
                DbExpression secondExpression = left.Not().And(right); 
                DbExpression result = firstExpression.Or(secondExpression); 
                return result;
            } 
        }
        private sealed class NotTranslator : TypedTranslator
        {
            internal NotTranslator() 
                : base(ExpressionType.Not) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq) 
            { 
                DbExpression operand = parent.TranslateExpression(linq.Operand);
                if (TypeSemantics.IsBooleanType(operand.ResultType)) 
                {
                    return operand.Not();
                }
                return parent.CreateCanonicalFunction(ExpressionConverter.BitwiseNot, linq, operand); 
            }
        } 
        #endregion 

        #region Unary expression translators 
        private abstract class UnaryTranslator
            : TypedTranslator
        {
            protected UnaryTranslator(params ExpressionType[] nodeTypes) 
                : base(nodeTypes) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq) 
            { 
                return TranslateUnary(parent, linq, parent.TranslateExpression(linq.Operand));
            } 
            protected abstract DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand);
        }
        private sealed class QuoteTranslator : UnaryTranslator
        { 
            internal QuoteTranslator()
                : base(ExpressionType.Quote) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand) 
            {
                // simply return the operand: expressions compilations not cached for LINQ, so 
                // parameters are always bound properly
                return operand;
            }
        } 
        private sealed class ConvertTranslator : UnaryTranslator
        { 
            internal ConvertTranslator() 
                : base(ExpressionType.Convert, ExpressionType.ConvertChecked) { }
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand) 
            {
                Type toClrType = unary.Type;
                Type fromClrType = unary.Operand.Type;
                DbExpression cast = parent.CreateCastExpression(operand, toClrType, fromClrType); 
                return cast;
            } 
        } 
        private sealed class AsTranslator : UnaryTranslator
        { 
            internal AsTranslator()
                : base(ExpressionType.TypeAs) { }
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
            { 
                TypeUsage fromType = operand.ResultType;
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeAs, unary.Type, unary.Operand.Type); 
                return operand.TreatAs(toType); 
            }
        } 
        #endregion
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System.Data.Common.CommandTrees;
using System.Collections.Generic; 
using System.Diagnostics;
using System.Data.Metadata.Edm;
using System.Linq.Expressions;
using System.Reflection; 
using System.Data.Objects.DataClasses;
using System.Globalization; 
using System.Data.Entity; 
using System.Data.Common.CommandTrees.ExpressionBuilder;
using System.Linq; 
namespace System.Data.Objects.ELinq
{
    internal sealed partial class ExpressionConverter
    { 
        // Base class supporting the translation of LINQ node type(s) given a LINQ expression
        // of that type, and the "parent" translation context (the ExpressionConverter processor) 
        private abstract class Translator 
        {
            private readonly ExpressionType[] _nodeTypes; 
            protected Translator(params ExpressionType[] nodeTypes)
            {
                _nodeTypes = nodeTypes;
            } 
            // Gets LINQ node types this translator should be registed to process.
            internal IEnumerable NodeTypes { get { return _nodeTypes; } } 
            internal abstract DbExpression Translate(ExpressionConverter parent, Expression linq); 
            public override string ToString()
            { 
                return this.GetType().Name;
            }
        }
 
        #region Misc
        // Typed version of Translator 
        private abstract class TypedTranslator : Translator 
            where T_Linq : Expression
        { 
            protected TypedTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { }
            internal override DbExpression Translate(ExpressionConverter parent, Expression linq)
            { 
                return TypedTranslate(parent, (T_Linq)linq);
            } 
            protected abstract DbExpression TypedTranslate(ExpressionConverter parent, T_Linq linq); 
        }
        private sealed class ConstantTranslator 
            : TypedTranslator
        {
            internal ConstantTranslator()
                : base(ExpressionType.Constant) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
            { 
                // Check to see if this constant corresponds to the compiled query context parameter (it 
                // gets turned into a constant during funcletization and has special error handling).
                if (linq == parent._funcletizer.RootContextExpression) 
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnsupportedUseOfContextParameter(
                        parent._funcletizer.RootContextParameter.Name));
                } 

                ObjectQuery queryOfT = linq.Value as ObjectQuery; 
                if (null != queryOfT) 
                {
                    return parent.TranslateInlineQueryOfT(queryOfT); 
                }

                // If it is something we can enumerate then we can evaluate locally and send to the server
                var values = linq.Value as System.Collections.IEnumerable; 
                if (values != null)
                { 
                    Type elementType = TypeSystem.GetElementType(linq.Type); 
                    if ((elementType != null) && (elementType != linq.Type))
                    { 
                        var expressions = new List();
                        foreach (object o in values)
                        {
                            expressions.Add(Expression.Constant(o, elementType)); 
                        }
 
                        // Invalidate the query plan every time the query is executed since it is possible 
                        // to modify an element of a collection without changing the reference.
                        parent._recompileRequired = () => true; 

                        return parent.TranslateExpression(Expression.NewArrayInit(elementType, expressions));
                    }
                } 

                bool isNullValue = null == linq.Value; 
 
                // Remove facet information: null instances do not constrain type facets (e.g. a null string does not restrict
                // "length" in compatibility checks) 
                TypeUsage type;
                bool typeSupported = false;
                if (parent.TryGetValueLayerType(linq.Type, out type))
                { 
                    // For constant values, support only primitive type (this is all that is supported by CQTs)
                    // For null types, also allow EntityType. Although other types claim to be supported, they 
                    // don't work (e.g. complex type, see SQL BU 543956) 
                    if (type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType ||
                        (isNullValue && type.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)) 
                    {
                        typeSupported = true;
                    }
                } 

                if (!typeSupported) 
                { 
                    throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedConstant(DescribeClrType(linq.Type), Strings.ELinq_PrimitiveTypesSample));
                } 

                // create a constant or null expression depending on value
                if (isNullValue)
                { 
                    return DbExpressionBuilder.Null(type);
                } 
                else 
                {
                    return DbExpressionBuilder.Constant(type, linq.Value); 
                }
            }
        }
        private sealed class MemberAccessTranslator 
            : TypedTranslator
        { 
            internal MemberAccessTranslator() 
                : base(ExpressionType.MemberAccess) { }
            // attempt to translate the member access to a "regular" property, a navigation property, or a calculated 
            // property
            protected override DbExpression TypedTranslate(ExpressionConverter parent, MemberExpression linq)
            {
                DbExpression propertyExpression; 
                string memberName;
                Type memberType; 
                MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Member, out memberName, out memberType); 

                // note: we check for "regular" properties last, since the other two flavors derive 
                // from this one
                if (linq.Expression != null)
                {
                    DbExpression instance = parent.TranslateExpression(linq.Expression); 
                    if (TryResolveAsProperty(parent, memberInfo,
                        instance.ResultType, instance, out propertyExpression)) 
                    { 
                        return propertyExpression;
                    } 
                }

                if (memberInfo.MemberType == MemberTypes.Property)
                { 
                    // Check whether it is one of the special properties that we know how to translate
                    PropertyTranslator propertyTranslator; 
                    if (TryGetTranslator((PropertyInfo)memberInfo, out propertyTranslator)) 
                    {
                        return propertyTranslator.Translate(parent, linq); 
                    }
                }

                // no other property types are supported by LINQ over entities 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnrecognizedMember(linq.Member.Name));
            } 
 
            #region Static members and initializers
            private static readonly Dictionary s_propertyTranslators; 
            private static bool s_vbPropertiesInitialized;
            private static readonly object s_vbInitializerLock = new object();

            static MemberAccessTranslator() 
            {
                // initialize translators for specific properties 
                s_propertyTranslators = new Dictionary(); 
                foreach (PropertyTranslator translator in GetPropertyTranslators())
                { 
                    foreach (PropertyInfo property in translator.Properties)
                    {
                        s_propertyTranslators.Add(property, translator);
                    } 
                }
            } 
 
            /// 
            /// Tries to get a translator for the given property info. 
            /// If the given property info corresponds to a Visual Basic property,
            /// it also initializes the Visual Basic translators if they have not been initialized
            /// 
            ///  
            /// 
            ///  
            private static bool TryGetTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator) 
            {
                //If the type is generic, we try to match the generic property 
                PropertyInfo nonGenericPropertyInfo = propertyInfo;
                if (propertyInfo.DeclaringType.IsGenericType)
                {
                    try 
                    {
                        propertyInfo = propertyInfo.DeclaringType.GetGenericTypeDefinition().GetProperty(propertyInfo.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); 
                    } 
                    catch (AmbiguousMatchException)
                    { 
                        propertyTranslator = null;
                        return false;
                    }
                    if (propertyInfo == null) 
                    {
                        propertyTranslator = null; 
                        return false; 
                    }
                } 

                PropertyTranslator translatorInstance;
                if (s_propertyTranslators.TryGetValue(propertyInfo, out translatorInstance))
                { 
                    propertyTranslator = translatorInstance;
                    return true; 
                } 

                // check if this is the visual basic assembly 
                if (s_visualBasicAssemblyFullName == propertyInfo.DeclaringType.Assembly.FullName)
                {
                    lock (s_vbInitializerLock)
                    { 
                        if (!s_vbPropertiesInitialized)
                        { 
                            InitializeVBProperties(propertyInfo.DeclaringType.Assembly); 
                            s_vbPropertiesInitialized = true;
                        } 
                        // try again
                        if (s_propertyTranslators.TryGetValue(propertyInfo, out translatorInstance))
                        {
                            propertyTranslator = translatorInstance; 
                            return true;
                        } 
                        else 
                        {
                            propertyTranslator = null; 
                            return false;
                        }
                    }
                } 

                if (GenericICollectionTranslator.TryGetPropertyTranslator(nonGenericPropertyInfo, out propertyTranslator)) 
                { 
                    return true;
                } 

                propertyTranslator = null;
                return false;
            } 

            // Determines if the given property can be resolved as a standard or navigation property. 
            private static bool TryResolveAsProperty(ExpressionConverter parent, 
                MemberInfo clrMember, TypeUsage definingType, DbExpression instance, out DbExpression propertyExpression)
            { 
                // retrieve members directly from row types, which are not mapped between O and C
                RowType rowType = definingType.EdmType as RowType;
                string name = clrMember.Name;
 
                if (null != rowType)
                { 
                    EdmMember member; 
                    if (rowType.Members.TryGetValue(name, false, out member))
                    { 
                        propertyExpression = instance.Property(name);
                        return true;
                    }
 
                    propertyExpression = null;
                    return false; 
                } 

                // for non-row structural types, map from the O to the C layer using the perspective 
                StructuralType structuralType = definingType.EdmType as StructuralType;
                if (null != structuralType)
                {
                    EdmMember member = null; 
                    if (parent._perspective.TryGetMember(structuralType, name, false, out member))
                    { 
                        if (null != member) 
                        {
                            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty) 
                            {
                                NavigationProperty navProp = (NavigationProperty)member;
                                propertyExpression = TranslateNavigationProperty(parent, clrMember, instance, navProp);
                                return true; 
                            }
                            else 
                            { 
                                propertyExpression = instance.Property(name);
                                return true; 
                            }

                        }
                    } 
                }
 
                // try to unwrap GroupBy "Key" member 
                if (name == ExpressionConverter.KeyColumnName)
                { 
                    // see if we can "unwrap" the current instance
                    if (DbExpressionKind.Property == instance.ExpressionKind)
                    {
                        DbPropertyExpression property = (DbPropertyExpression)instance; 
                        InitializerMetadata initializerMetadata;
 
                        // if we're dealing with the "Group" property of a GroupBy projection, we know how to unwrap 
                        // it
                        if (property.Property.Name == ExpressionConverter.GroupColumnName && // only know how to unwrap the group 
                            InitializerMetadata.TryGetInitializerMetadata(property.Instance.ResultType, out initializerMetadata) &&
                            initializerMetadata.Kind == InitializerMetadataKind.Grouping)
                        {
                            propertyExpression = property.Instance.Property(ExpressionConverter.KeyColumnName); 
                            return true;
                        } 
                    } 
                }
 
                propertyExpression = null;
                return false;
            }
 
            private static DbExpression TranslateNavigationProperty(ExpressionConverter parent, MemberInfo clrMember, DbExpression instance, NavigationProperty navProp)
            { 
                DbExpression propertyExpression; 
                propertyExpression = instance.Property(navProp);
 
                // for EntityCollection navigations, wrap in "grouping" where the key is the parent
                // entity and the group contains the child entities
                // For non-EntityCollection navigations (e.g. from POCO entities), we just need the
                // enumeration, not the grouping 
                if (BuiltInTypeKind.CollectionType == propertyExpression.ResultType.EdmType.BuiltInTypeKind)
                { 
                    Debug.Assert(clrMember is PropertyInfo, "Navigation property was not a property; should not be allowed by metadata."); 
                    Type propertyType = ((PropertyInfo)clrMember).PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>)) 
                    {
                        List> collectionColumns =
                            new List>(2);
                        collectionColumns.Add(new KeyValuePair( 
                            ExpressionConverter.EntityCollectionOwnerColumnName, instance));
                        collectionColumns.Add(new KeyValuePair( 
                            ExpressionConverter.EntityCollectionElementsColumnName, propertyExpression)); 
                        propertyExpression = parent.CreateNewRowExpression(collectionColumns,
                            InitializerMetadata.CreateEntityCollectionInitializer(parent.EdmItemCollection, ((PropertyInfo)clrMember).PropertyType, navProp)); 
                    }
                }
                return propertyExpression;
            } 

            private static DbExpression TranslateCount(ExpressionConverter parent, Type sequenceElementType, Expression sequence) 
            { 
                // retranslate as a Count() aggregate, since the name collision prevents us
                // from calling the method directly in VB and C# 
                MethodInfo countMethod;
                ReflectionUtil.TryLookupMethod(SequenceMethod.Count, out countMethod);
                Debug.Assert(null != countMethod, "Count() must exist");
                countMethod = countMethod.MakeGenericMethod(sequenceElementType); 
                Expression countCall = Expression.Call(countMethod, sequence);
                return parent.TranslateExpression(countCall); 
            } 

            private static void InitializeVBProperties(Assembly vbAssembly) 
            {
                Debug.Assert(!s_vbPropertiesInitialized);
                foreach (PropertyTranslator translator in GetVisualBasicPropertyTranslators(vbAssembly))
                { 
                    foreach (PropertyInfo property in translator.Properties)
                    { 
                        s_propertyTranslators.Add(property, translator); 
                    }
                } 
            }

            private static IEnumerable GetVisualBasicPropertyTranslators(Assembly vbAssembly)
            { 
                yield return new VBDateAndTimeNowTranslator(vbAssembly);
            } 
 
            private static IEnumerable GetPropertyTranslators()
            { 
                yield return new DefaultCanonicalFunctionPropertyTranslator();
                yield return new RenameCanonicalFunctionPropertyTranslator();
                yield return new EntityCollectionCountTranslator();
                yield return new NullableHasValueTranslator(); 
                yield return new NullableValueTranslator();
            } 
 
            /// 
            /// This method is used to determine whether client side evaluation should be done, 
            /// if the property can be evaluated in the store, it is not being evaluated on the client
            /// 
            internal static bool CanFuncletizePropertyInfo(PropertyInfo propertyInfo)
            { 
                PropertyTranslator propertyTranslator;
                // In most cases, we only allow funcletization of properties that could not otherwise be 
                // handled by the query pipeline. ICollection<>.Count is the one exception to the rule 
                // (avoiding a breaking change)
                return GenericICollectionTranslator.TryGetPropertyTranslator(propertyInfo, out propertyTranslator) || 
                    !TryGetTranslator(propertyInfo, out propertyTranslator);
            }
            #endregion
 
            #region Dynamic Property Translators
 
            private sealed class GenericICollectionTranslator : PropertyTranslator 
            {
                private readonly Type _elementType; 

                private GenericICollectionTranslator(Type elementType) : base(Enumerable.Empty())
                {
                    _elementType = elementType; 
                }
 
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    return TranslateCount(parent, _elementType, call.Expression); 
                }

                internal static bool TryGetPropertyTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator)
                { 
                    // Implementation note: When adding support for additional properties, use less expensive checks
                    // such as property name and return type to test for a property defined by ICollection first 
                    // before calling the more expensive TypeSystem.FindICollection to test whether the declaring type 
                    // of the property implements ICollection.
 
                    //
                    // Int32 Count
                    //
                    if (propertyInfo.Name == "Count" && 
                        propertyInfo.PropertyType.Equals(typeof(int)))
                    { 
                        foreach (KeyValuePair implementedCollectionInfo in GetImplementedICollections(propertyInfo.DeclaringType)) 
                        {
                            Type implementedCollection = implementedCollectionInfo.Key; 
                            Type elementType = implementedCollectionInfo.Value;

                            if (propertyInfo.IsImplementationOf(implementedCollection))
                            { 
                                propertyTranslator = new GenericICollectionTranslator(elementType);
                                return true; 
                            } 
                        }
                    } 

                    // Not a supported ICollection property
                    propertyTranslator = null;
                    return false; 
                }
 
                private static bool IsICollection(Type candidateType, out Type elementType) 
                {
                    if (candidateType.IsGenericType && 
                        candidateType.GetGenericTypeDefinition().Equals(typeof(System.Collections.Generic.ICollection<>)))
                    {
                        elementType = candidateType.GetGenericArguments()[0];
                        return true; 
                    }
                    elementType = null; 
                    return false; 
                }
 
                private static IEnumerable> GetImplementedICollections(Type type)
                {
                    Type collectionElementType;
                    if (IsICollection(type, out collectionElementType)) 
                    {
                        yield return new KeyValuePair(type, collectionElementType); 
                    } 
                    else
                    { 
                        foreach (Type interfaceType in type.GetInterfaces())
                        {
                            if (IsICollection(interfaceType, out collectionElementType))
                            { 
                                yield return new KeyValuePair(interfaceType, collectionElementType);
                            } 
                        } 
                    }
                } 
            }

            #endregion
 
            #region Signature-based Property Translators
            private abstract class PropertyTranslator 
            { 
                private readonly IEnumerable _properties;
                protected PropertyTranslator(params PropertyInfo[] properties) { _properties = properties; } 
                protected PropertyTranslator(IEnumerable properties) { _properties = properties; }
                internal IEnumerable Properties { get { return _properties; } }
                internal abstract DbExpression Translate(ExpressionConverter parent, MemberExpression call);
                public override string ToString() 
                {
                    return GetType().Name; 
                } 
            }
 
            private sealed class DefaultCanonicalFunctionPropertyTranslator : PropertyTranslator
            {
                internal DefaultCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties() 
                { 
                    yield return typeof(String).GetProperty("Length", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance); 
 
                    yield return typeof(DateTimeOffset).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);
                } 
 
                // Default translator for method calls into canonical functions.
                // Translation: 
                //      object.PropertyName  -> PropertyName(object)
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
                {
                    return parent.TranslateIntoCanonicalFunction(call.Member.Name, call, call.Expression); 
                }
            } 
 
            private sealed class RenameCanonicalFunctionPropertyTranslator : PropertyTranslator
            { 
                private static readonly Dictionary s_propertyRenameMap = new Dictionary(2);

                internal RenameCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties() 
                { 
                    yield return GetProperty(typeof(DateTime), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTime);
                    yield return GetProperty(typeof(DateTime), "UtcNow", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentUtcDateTime); 
                    yield return GetProperty(typeof(DateTimeOffset), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTimeOffset);

                    yield return GetProperty(typeof(TimeSpan), "Hours", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Hour);
                    yield return GetProperty(typeof(TimeSpan), "Minutes", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Minute); 
                    yield return GetProperty(typeof(TimeSpan), "Seconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Second);
                    yield return GetProperty(typeof(TimeSpan), "Milliseconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Millisecond); 
                } 

                private static PropertyInfo GetProperty(Type declaringType, string propertyName, BindingFlags bindingFlages, string canonicalFunctionName) 
                {
                    PropertyInfo propertyInfo = declaringType.GetProperty(propertyName, bindingFlages);
                    s_propertyRenameMap.Add(propertyInfo, canonicalFunctionName);
                    return propertyInfo; 
                }
 
                // Translator for static properties into canonical functions when there is a corresponding 
                // canonical function but with a differnet name
                // Translation: 
                //      object.PropertyName  -> CanonicalFunctionName(object)
                //      Type.PropertyName  -> CanonicalFunctionName()
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    PropertyInfo property = (PropertyInfo)call.Member;
                    String canonicalFunctionName = s_propertyRenameMap[property]; 
                    DbExpression result; 
                    if (call.Expression == null)
                    { 
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call);
                    }
                    else
                    { 
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call, call.Expression);
                    } 
                    return result; 
                }
            } 

            private sealed class VBDateAndTimeNowTranslator : PropertyTranslator
            {
                private const string s_dateAndTimeTypeFullName = "Microsoft.VisualBasic.DateAndTime"; 

                internal VBDateAndTimeNowTranslator(Assembly vbAssembly) 
                    : base(GetProperty(vbAssembly)) { } 

                private static PropertyInfo GetProperty(Assembly vbAssembly) 
                {
                    return vbAssembly.GetType(s_dateAndTimeTypeFullName).GetProperty("Now", BindingFlags.Public | BindingFlags.Static);
                }
 
                // Translation:
                //      Now -> GetDate() 
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    return parent.TranslateIntoCanonicalFunction(ExpressionConverter.CurrentDateTime, call); 
                }
            }

            private sealed class EntityCollectionCountTranslator : PropertyTranslator 
            {
                internal EntityCollectionCountTranslator() 
                    : base(GetProperty()) { } 

                private static PropertyInfo GetProperty() 
                {
                    return typeof(EntityCollection<>).GetProperty(ExpressionConverter.s_entityCollectionCountPropertyName, BindingFlags.Public | BindingFlags.Instance);
                }
 
                // Translation:
                //      EntityCollection.Count -> Count() 
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    // retranslate as a Count() aggregate, since the name collision prevents us 
                    // from calling the method directly in VB and C#
                    return MemberAccessTranslator.TranslateCount(parent, call.Member.DeclaringType.GetGenericArguments()[0], call.Expression);
                }
            } 

            private sealed class NullableHasValueTranslator : PropertyTranslator 
            { 
                internal NullableHasValueTranslator()
                    : base(GetProperty()) { } 

                private static PropertyInfo GetProperty()
                {
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableHasValuePropertyName, BindingFlags.Public | BindingFlags.Instance); 
                }
 
                // Translation: 
                //      Nullable.HasValue -> Not(IsNull(arg))
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    DbExpression argument = parent.TranslateExpression(call.Expression);
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type");
                    return parent.CreateIsNullExpression(argument, call.Expression.Type).Not(); 
                }
            } 
 
            private sealed class NullableValueTranslator : PropertyTranslator
            { 
                internal NullableValueTranslator()
                    : base(GetProperty()) { }

                private static PropertyInfo GetProperty() 
                {
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableValuePropertyName, BindingFlags.Public | BindingFlags.Instance); 
                } 

                // Translation: 
                //      Nullable.Value -> arg
                internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
                {
                    DbExpression argument = parent.TranslateExpression(call.Expression); 
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type");
                    return argument; 
                } 
            }
            #endregion 
        }
        private sealed class ParameterTranslator
            : TypedTranslator
        { 
            internal ParameterTranslator()
                : base(ExpressionType.Parameter) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ParameterExpression linq) 
            {
                // Bindings should be intercepted before we get to this point (in ExpressionConverter.TranslateExpression) 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnboundParameterExpression(linq.Name));
            }
        }
        private sealed class NewTranslator 
            : TypedTranslator
        { 
            internal NewTranslator() 
                : base(ExpressionType.New) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, NewExpression linq) 
            {
                int memberCount = null == linq.Members ? 0 : linq.Members.Count;

                if (null == linq.Constructor || 
                    linq.Arguments.Count != memberCount)
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor); 
                }
 
                parent.CheckInitializerType(linq.Type);

                List> recordColumns =
                    new List>(memberCount + 1); 

                HashSet memberNames = new HashSet(StringComparer.Ordinal); 
                for (int i = 0; i < memberCount; i++) 
                {
                    string memberName; 
                    Type memberType;
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Members[i], out memberName, out memberType);
                    DbExpression memberValue = parent.TranslateExpression(linq.Arguments[i]);
                    memberNames.Add(memberName); 
                    recordColumns.Add(new KeyValuePair(memberName, memberValue));
                } 
 
                InitializerMetadata initializerMetadata;
                if (0 == memberCount) 
                {
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(DbExpressionBuilder.True.As(KeyColumnName));
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq); 
                }
                else 
                { 
                    // Construct a new initializer type in metadata for this projection (provides the
                    // necessary context for the object materializer) 
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq);
                }
                parent.ValidateInitializerMetadata(initializerMetadata);
 
                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata);
 
                return projection; 
            }
        } 
        private sealed class NewArrayInitTranslator
            : TypedTranslator
        {
            internal NewArrayInitTranslator() 
                : base(ExpressionType.NewArrayInit) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, NewArrayExpression linq) 
            { 
                if (linq.Expressions.Count > 0)
                { 
                    return DbExpressionBuilder.NewCollection(linq.Expressions.Select(e => parent.TranslateExpression(e)));
                }

                TypeUsage typeUsage; 
                if (parent.TryGetValueLayerType(linq.Type, out typeUsage))
                { 
                    return DbExpressionBuilder.NewEmptyCollection(typeUsage); 
                }
 
                throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedType(DescribeClrType(linq.Type)));
            }
        }
        private sealed class ListInitTranslator 
            : TypedTranslator
        { 
            internal ListInitTranslator() 
                : base(ExpressionType.ListInit ) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ListInitExpression linq) 
            {
                // Ensure requirements: one list initializer argument and a default constructor.
                if ((linq.NewExpression.Constructor != null) && (linq.NewExpression.Constructor.GetParameters().Length != 0))
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
                } 
 
                if (linq.Initializers.Any(i => i.Arguments.Count != 1))
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedInitializers);
                }

                return DbExpressionBuilder.NewCollection(linq.Initializers.Select(i => parent.TranslateExpression(i.Arguments[0]))); 
            }
        } 
        private sealed class MemberInitTranslator 
            : TypedTranslator
        { 
            internal MemberInitTranslator()
                : base(ExpressionType.MemberInit) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)
            { 
                if (null == linq.NewExpression.Constructor ||
                    0 != linq.NewExpression.Constructor.GetParameters().Length) 
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
                } 

                parent.CheckInitializerType(linq.Type);

                List> recordColumns = 
                    new List>(linq.Bindings.Count + 1);
                MemberInfo[] members = new MemberInfo[linq.Bindings.Count]; 
 
                HashSet memberNames = new HashSet(StringComparer.Ordinal);
                for (int i = 0; i < linq.Bindings.Count; i++) 
                {
                    MemberAssignment binding = linq.Bindings[i] as MemberAssignment;
                    if (null == binding)
                    { 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedBinding);
                    } 
                    string memberName; 
                    Type memberType;
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(binding.Member, out memberName, out memberType); 

                    DbExpression memberValue = parent.TranslateExpression(binding.Expression);
                    memberNames.Add(memberName);
                    members[i] = memberInfo; 
                    recordColumns.Add(new KeyValuePair(memberName, memberValue));
                } 
 
                InitializerMetadata initializerMetadata;
 
                if (0 == recordColumns.Count)
                {
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(DbExpressionBuilder.Constant(true).As(KeyColumnName)); 
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq.NewExpression);
                } 
                else 
                {
                    // Construct a new initializer type in metadata for this projection (provides the 
                    // necessary context for the object materializer)
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq, members);
                }
                parent.ValidateInitializerMetadata(initializerMetadata); 
                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata);
 
                return projection; 
            }
        } 
        private sealed class ConditionalTranslator : TypedTranslator
        {
            internal ConditionalTranslator()
                : base(ExpressionType.Conditional) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, ConditionalExpression linq)
            { 
                // translate Test ? IfTrue : IfFalse --> CASE WHEN Test THEN IfTrue ELSE IfFalse 
                List whenExpressions = new List(1);
                whenExpressions.Add(parent.TranslateExpression(linq.Test)); 
                List thenExpressions = new List(1);
                thenExpressions.Add(parent.TranslateExpression(linq.IfTrue));
                DbExpression elseExpression = parent.TranslateExpression(linq.IfFalse);
                return DbExpressionBuilder.Case(whenExpressions, thenExpressions, elseExpression); 
            }
        } 
        private sealed class NotSupportedTranslator : Translator 
        {
            internal NotSupportedTranslator(params ExpressionType[] nodeTypes) 
                : base(nodeTypes)
            {
            }
            internal override DbExpression Translate(ExpressionConverter parent, Expression linq) 
            {
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType)); 
            } 
        }
        private sealed class ExtensionTranslator : Translator 
        {
            internal ExtensionTranslator()
                : base(EntityExpressionVisitor.CustomExpression)
            { 
            }
            internal override DbExpression Translate(ExpressionConverter parent, Expression linq) 
            { 
                QueryParameterExpression queryParameter = linq as QueryParameterExpression;
                if (null == queryParameter) 
                {
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType));
                }
                // otherwise add a new query parameter... 
                parent.AddParameter(queryParameter);
                return queryParameter.ParameterReference; 
            } 
        }
        #endregion 

        #region Binary expression translators
        private abstract class BinaryTranslator
            : TypedTranslator 
        {
            protected BinaryTranslator(params ExpressionType[] nodeTypes) 
                : base(nodeTypes) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            { 
                return TranslateBinary(parent, parent.TranslateExpression(linq.Left), parent.TranslateExpression(linq.Right), linq);
            }
            protected abstract DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq);
        } 
        private sealed class CoalesceTranslator : BinaryTranslator
        { 
            internal CoalesceTranslator() 
                : base(ExpressionType.Coalesce) { }
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq) 
            {
                // left ?? right gets translated to:
                // CASE WHEN IsNull(left) THEN right ELSE left
 
                // construct IsNull
                DbExpression isNull = parent.CreateIsNullExpression(left, linq.Left.Type); 
 
                // construct case expression
                List whenExpressions = new List(1); 
                whenExpressions.Add(isNull);
                List thenExpressions = new List(1);
                thenExpressions.Add(right);
                DbExpression caseExpression = DbExpressionBuilder.Case(whenExpressions, 
                    thenExpressions, left);
 
                return caseExpression; 
            }
        } 
        private sealed class AndAlsoTranslator : BinaryTranslator
        {
            internal AndAlsoTranslator()
                : base(ExpressionType.AndAlso) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.And(right); 
            }
        } 
        private sealed class OrElseTranslator : BinaryTranslator
        {
            internal OrElseTranslator()
                : base(ExpressionType.OrElse) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Or(right); 
            }
        } 
        private sealed class LessThanTranslator : BinaryTranslator
        {
            internal LessThanTranslator()
                : base(ExpressionType.LessThan) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.LessThan(right); 
            }
        } 
        private sealed class LessThanOrEqualsTranslator : BinaryTranslator
        {
            internal LessThanOrEqualsTranslator()
                : base(ExpressionType.LessThanOrEqual) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.LessThanOrEqual(right); 
            }
        } 
        private sealed class GreaterThanTranslator : BinaryTranslator
        {
            internal GreaterThanTranslator()
                : base(ExpressionType.GreaterThan) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.GreaterThan(right); 
            }
        } 
        private sealed class GreaterThanOrEqualsTranslator : BinaryTranslator
        {
            internal GreaterThanOrEqualsTranslator()
                : base(ExpressionType.GreaterThanOrEqual) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.GreaterThanOrEqual(right); 
            }
        } 
        private sealed class EqualsTranslator : TypedTranslator
        {
            internal EqualsTranslator()
                : base(ExpressionType.Equal) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            { 
                Expression linqLeft = linq.Left; 
                Expression linqRight = linq.Right;
 
                bool leftIsNull = ExpressionIsNullConstant(linqLeft);
                bool rightIsNull = ExpressionIsNullConstant(linqRight);

                // if both values are null, short-circuit 
                if (leftIsNull && rightIsNull) { return DbExpressionBuilder.True; }
 
                // if only one side is null, produce an IsNull statement 
                if (leftIsNull) { return CreateIsNullExpression(parent, linqRight); }
                if (rightIsNull) { return CreateIsNullExpression(parent, linqLeft); } 

                // create a standard equals expression, calling utility method to compensate for null equality
                DbExpression cqtLeft = parent.TranslateExpression(linqLeft);
                DbExpression cqtRight = parent.TranslateExpression(linqRight); 
                return parent.CreateEqualsExpression(cqtLeft, cqtRight, EqualsPattern.Store, linqLeft.Type, linqRight.Type);
            } 
            private static DbExpression CreateIsNullExpression(ExpressionConverter parent, Expression input) 
            {
                input = UnwrapConvert(input); 

                // translate input
                DbExpression inputCqt = parent.TranslateExpression(input);
 
                // create IsNull expression
                return parent.CreateIsNullExpression(inputCqt, input.Type); 
            } 
            private static bool ExpressionIsNullConstant(Expression expression)
            { 
                // convert statements introduced by compiler should not affect nullness
                expression = UnwrapConvert(expression);

                // check if the unwrapped expression is a null constant 
                if (ExpressionType.Constant != expression.NodeType) { return false; }
                System.Linq.Expressions.ConstantExpression constant = (System.Linq.Expressions.ConstantExpression)expression; 
                return null == constant.Value; 
            }
            private static Expression UnwrapConvert(Expression input) 
            {
                // unwrap all converts
                while (ExpressionType.Convert == input.NodeType)
                { 
                    input = ((UnaryExpression)input).Operand;
                } 
                return input; 
            }
        } 
        private sealed class NotEqualsTranslator : TypedTranslator
        {
            internal NotEqualsTranslator()
                : base(ExpressionType.NotEqual) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            { 
                // rewrite as a not equals expression 
                Expression notLinq = Expression.Not(
                    Expression.Equal(linq.Left, linq.Right)); 
                return parent.TranslateExpression(notLinq);
            }
        }
        #endregion 

        #region Type binary expression translator 
        private sealed class IsTranslator : TypedTranslator 
        {
            internal IsTranslator() 
                : base(ExpressionType.TypeIs) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, TypeBinaryExpression linq)
            {
                DbExpression operand = parent.TranslateExpression(linq.Expression); 
                TypeUsage fromType = operand.ResultType;
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeIs, linq.TypeOperand, linq.Expression.Type); 
                return operand.IsOf(toType); 
            }
        } 
        #endregion

        #region Arithmetic expressions
        private sealed class AddTranslator : BinaryTranslator 
        {
            internal AddTranslator() 
                : base(ExpressionType.Add, ExpressionType.AddChecked) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                if (TypeSemantics.IsPrimitiveType(left.ResultType, PrimitiveTypeKind.String) &&
                   TypeSemantics.IsPrimitiveType(right.ResultType, PrimitiveTypeKind.String))
                {
                    // Add(string, string) => Concat(string, string) 
                    return parent.CreateCanonicalFunction(ExpressionConverter.Concat, linq, left, right);
                } 
                else 
                {
                    return left.Plus(right); 
                }
            }
        }
        private sealed class DivideTranslator : BinaryTranslator 
        {
            internal DivideTranslator() 
                : base(ExpressionType.Divide) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Divide(right);
            }
        }
        private sealed class ModuloTranslator : BinaryTranslator 
        {
            internal ModuloTranslator() 
                : base(ExpressionType.Modulo) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Modulo(right);
            }
        }
        private sealed class MultiplyTranslator : BinaryTranslator 
        {
            internal MultiplyTranslator() 
                : base(ExpressionType.Multiply, ExpressionType.MultiplyChecked) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Multiply(right);
            }
        }
        private sealed class SubtractTranslator : BinaryTranslator 
        {
            internal SubtractTranslator() 
                : base(ExpressionType.Subtract, ExpressionType.SubtractChecked) { } 
            protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
            { 
                return left.Minus(right);
            }
        }
        private sealed class NegateTranslator : UnaryTranslator 
        {
            internal NegateTranslator() 
                : base(ExpressionType.Negate, ExpressionType.NegateChecked) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
            { 
                return operand.UnaryMinus();
            }
        }
        private sealed class UnaryPlusTranslator : UnaryTranslator 
        {
            internal UnaryPlusTranslator() 
                : base(ExpressionType.UnaryPlus) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, UnaryExpression unary, DbExpression operand)
            { 
                // +x = x
                return operand;
            }
        } 
        #endregion
 
        #region Bitwise expressions 
        private abstract class BitwiseBinaryTranslator : TypedTranslator
        { 
            private readonly string _canonicalFunctionName;

            protected BitwiseBinaryTranslator(ExpressionType nodeType, string canonicalFunctionName)
                : base(nodeType) 
            {
                _canonicalFunctionName = canonicalFunctionName; 
            } 

            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq) 
            {
                DbExpression left = parent.TranslateExpression(linq.Left);
                DbExpression right = parent.TranslateExpression(linq.Right);
 
                //If the arguments are binary we translate into logic expressions
                if (TypeSemantics.IsBooleanType(left.ResultType)) 
                { 
                    return TranslateIntoLogicExpression(parent, linq, left, right);
                } 

                //Otherwise we translate into bitwise canonical functions
                return parent.CreateCanonicalFunction(_canonicalFunctionName, linq, left, right);
            } 
            protected abstract DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right);
        } 
        private sealed class AndTranslator : BitwiseBinaryTranslator 
        {
            internal AndTranslator() 
                : base(ExpressionType.And, ExpressionConverter.BitwiseAnd) { }
            protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
            {
                return left.And(right); 
            }
        } 
        private sealed class OrTranslator : BitwiseBinaryTranslator 
        {
            internal OrTranslator() 
                : base(ExpressionType.Or, ExpressionConverter.BitwiseOr) { }
            protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
            {
                return left.Or(right); 
            }
        } 
        private sealed class ExclusiveOrTranslator : BitwiseBinaryTranslator 
        {
            internal ExclusiveOrTranslator() 
                : base(ExpressionType.ExclusiveOr, ExpressionConverter.BitwiseXor) { }
            protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
            {
                //No direct translation, we translate into ((left && !right) || (!left && right)) 
                DbExpression firstExpression = left.And(right.Not());
                DbExpression secondExpression = left.Not().And(right); 
                DbExpression result = firstExpression.Or(secondExpression); 
                return result;
            } 
        }
        private sealed class NotTranslator : TypedTranslator
        {
            internal NotTranslator() 
                : base(ExpressionType.Not) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq) 
            { 
                DbExpression operand = parent.TranslateExpression(linq.Operand);
                if (TypeSemantics.IsBooleanType(operand.ResultType)) 
                {
                    return operand.Not();
                }
                return parent.CreateCanonicalFunction(ExpressionConverter.BitwiseNot, linq, operand); 
            }
        } 
        #endregion 

        #region Unary expression translators 
        private abstract class UnaryTranslator
            : TypedTranslator
        {
            protected UnaryTranslator(params ExpressionType[] nodeTypes) 
                : base(nodeTypes) { }
            protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq) 
            { 
                return TranslateUnary(parent, linq, parent.TranslateExpression(linq.Operand));
            } 
            protected abstract DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand);
        }
        private sealed class QuoteTranslator : UnaryTranslator
        { 
            internal QuoteTranslator()
                : base(ExpressionType.Quote) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand) 
            {
                // simply return the operand: expressions compilations not cached for LINQ, so 
                // parameters are always bound properly
                return operand;
            }
        } 
        private sealed class ConvertTranslator : UnaryTranslator
        { 
            internal ConvertTranslator() 
                : base(ExpressionType.Convert, ExpressionType.ConvertChecked) { }
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand) 
            {
                Type toClrType = unary.Type;
                Type fromClrType = unary.Operand.Type;
                DbExpression cast = parent.CreateCastExpression(operand, toClrType, fromClrType); 
                return cast;
            } 
        } 
        private sealed class AsTranslator : UnaryTranslator
        { 
            internal AsTranslator()
                : base(ExpressionType.TypeAs) { }
            protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
            { 
                TypeUsage fromType = operand.ResultType;
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeAs, unary.Type, unary.Operand.Type); 
                return operand.TreatAs(toType); 
            }
        } 
        #endregion
    }
}

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