FunctionDescription.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Parsing / FunctionDescription.cs / 1305376 / FunctionDescription.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides a class to represent system functions.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services.Parsing
{
    using System; 
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.Linq.Expressions; 
    using System.Reflection;
    using System.Data.Services.Providers; 

    /// Use this class to represent a system function for Astoria expressions.
    [DebuggerDisplay("FunctionDescription {name}")]
    internal class FunctionDescription 
    {
        /// Function name for type casts. 
        private const string FunctionNameCast = "cast"; 

        /// Function name for type checks. 
        private const string FunctionNameIsOf = "isof";

        /// CLR member for property or method invocation.
        private readonly MemberInfo member; 

        /// Function name. 
        private readonly string name; 

        /// Parameter types for method invocation. 
        private readonly Type[] parameterTypes;

        /// Conversion to expression for this function.
        private Func conversionFunction; 

        /// Initializes a new . 
        /// CLR member for property or method invocation. 
        /// Parameter types for method invocation.
        public FunctionDescription(MemberInfo member, Type[] parameterTypes) 
            : this(member, parameterTypes, null, member.Name)
        {
        }
 
        /// Initializes a new .
        /// Name for conversion function. 
        /// Parameter types for method invocation. 
        /// Conversion to expression for this function.
        public FunctionDescription(string name, Type[] parameterTypes, Func conversionFunction) 
            : this(null, parameterTypes, conversionFunction, name)
        {
        }
 
        /// Initializes a new .
        /// CLR member for property or method invocation. 
        /// Parameter types for method invocation. 
        /// Conversion to expression for this function.
        /// Name for conversion function. 
        private FunctionDescription(
            MemberInfo member,
            Type[] parameterTypes,
            Func conversionFunction, 
            string name)
        { 
            this.member = member; 
            this.parameterTypes = parameterTypes;
            this.conversionFunction = conversionFunction; 
            this.name = name;
        }

        /// Conversion to expression for this function. 
        public Func ConversionFunction
        { 
            [DebuggerStepThrough] 
            get { return this.conversionFunction; }
            [DebuggerStepThrough] 
            set { this.conversionFunction = value; }
        }

        /// Gets a value indicating whether this function is a typecast function. 
        public bool IsTypeCast
        { 
            get { return this.name == FunctionNameCast; } 
        }
 
        /// Gets a value indicating whether this function is a type check function.
        public bool IsTypeCheck
        {
            get { return this.name == FunctionNameIsOf; } 
        }
 
        /// Parameter types for method invocation. 
        public Type[] ParameterTypes
        { 
            [DebuggerStepThrough]
            get { return this.parameterTypes; }
        }
 
        /// Performs an instance method invocation.
        /// "it" expression; unused by this function. 
        /// Arguments for method invocation; first one should be the target 'this'. 
        /// A new expression with the method invocation.
        public Expression InstanceMethodConversionFunction(Expression target, Expression[] arguments) 
        {
            Expression instanceArgument = arguments[0];
            Expression[] methodArguments = new Expression[arguments.Length - 1];
            Array.Copy(arguments, 1, methodArguments, 0, arguments.Length - 1); 
            return Expression.Call(instanceArgument, (MethodInfo)this.member, methodArguments);
        } 
 
        /// Performs a static method invocation.
        /// "it" expression; unused by this function. 
        /// Arguments for method invocation.
        /// A new expression with the method invocation.
        public Expression StaticMethodConversionFunction(Expression target, Expression[] arguments)
        { 
            return Expression.Call((MethodInfo)this.member, arguments);
        } 
 
        /// Performs an instance property access.
        /// "it" expression; unused by this function. 
        /// Argument for property access; instance.
        /// A new expression with the property access.
        public Expression InstancePropertyConversionFunction(Expression target, Expression[] arguments)
        { 
            return Expression.Property(arguments[0], (PropertyInfo)this.member);
        } 
 
        /// 
        /// Invoke the open typed method for this function. 
        /// 
        /// list of parameters to pass to the late bound method.
        /// A new expression with the late bound function
        public Expression InvokeOpenTypeMethod(Expression[] arguments) 
        {
            Debug.Assert(arguments != null, "arguments != null"); 
            Debug.Assert(arguments.Length == this.ParameterTypes.Length, "arguments.Length == this.ParameterTypes.Length"); 

            Type[] argumentTypes = new Type[this.parameterTypes.Length]; 
            for (int i = 0; i < argumentTypes.Length; i++)
            {
                argumentTypes[i] = typeof(object);
            } 

            MethodInfo methodInfo = typeof(OpenTypeMethods).GetMethod( 
                this.name, 
                BindingFlags.Static | BindingFlags.Public,
                null, 
                argumentTypes,
                null);

            Debug.Assert(methodInfo != null, "methodInfo != null"); 
            return Expression.Call(null, methodInfo, arguments);
        } 
 
        /// Builds a list of function signatures.
        /// Function name. 
        /// Function descriptions.
        /// A string with ';'-separated list of function signatures.
        internal static string BuildSignatureList(string name, IEnumerable descriptions)
        { 
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            string descriptionSeparator = ""; 
            foreach (FunctionDescription description in descriptions) 
            {
                builder.Append(descriptionSeparator); 
                descriptionSeparator = "; ";

                string parameterSeparator = "";
                builder.Append(name); 
                builder.Append('(');
                foreach (Type type in description.ParameterTypes) 
                { 
                    builder.Append(parameterSeparator);
                    parameterSeparator = ", "; 

                    Type underlyingType = Nullable.GetUnderlyingType(type);
                    if (underlyingType != null)
                    { 
                        builder.Append(underlyingType.FullName);
                        builder.Append('?'); 
                    } 
                    else
                    { 
                        builder.Append(type.FullName);
                    }
                }
 
                builder.Append(')');
            } 
 
            return builder.ToString();
        } 

        /// Creates and populates a dictionary of system functions.
        /// A new dictionary of functions.
        internal static Dictionary CreateFunctions() 
        {
            Dictionary result = new Dictionary(StringComparer.Ordinal); 
 
            // String functions.
            FunctionDescription[] signatures; 
            result.Add("endswith", new FunctionDescription[] { StringInstanceFunction("EndsWith", typeof(string)) });
            result.Add("indexof", new FunctionDescription[] { StringInstanceFunction("IndexOf", typeof(string)) });
            result.Add("replace", new FunctionDescription[] { StringInstanceFunction("Replace", typeof(string), typeof(string)) });
            result.Add("startswith", new FunctionDescription[] { StringInstanceFunction("StartsWith", typeof(string)) }); 
            result.Add("tolower", new FunctionDescription[] { StringInstanceFunction("ToLower", Type.EmptyTypes) });
            result.Add("toupper", new FunctionDescription[] { StringInstanceFunction("ToUpper", Type.EmptyTypes) }); 
            result.Add("trim", new FunctionDescription[] { StringInstanceFunction("Trim", Type.EmptyTypes) }); 

            signatures = new FunctionDescription[] 
            {
                StringInstanceFunction("Substring", typeof(int)),
                StringInstanceFunction("Substring", typeof(int), typeof(int))
            }; 
            result.Add("substring", signatures);
 
            signatures = new FunctionDescription[] 
            {
                new FunctionDescription("SubstringOf", new Type[] { typeof(string), typeof(string) }, SubstringOf) 
            };
            result.Add("substringof", signatures);

            signatures = new FunctionDescription[] 
            {
                CreateFunctionDescription(typeof(string), false /* instance */, true /* method */, "Concat", typeof(string), typeof(string)) 
            }; 
            result.Add("concat", signatures);
 
            signatures = new FunctionDescription[]
            {
                CreateFunctionDescription(typeof(string), true /* instance */, false /* method */, "Length", Type.EmptyTypes)
            }; 
            result.Add("length", signatures);
 
            // DateTime functions. 
            result.Add("year", DateTimeFunctionArray("Year"));
            result.Add("month", DateTimeFunctionArray("Month")); 
            result.Add("day", DateTimeFunctionArray("Day"));
            result.Add("hour", DateTimeFunctionArray("Hour"));
            result.Add("minute", DateTimeFunctionArray("Minute"));
            result.Add("second", DateTimeFunctionArray("Second")); 

            // Mathematical functions. 
            result.Add("round", MathFunctionArray("Round")); 
            result.Add("floor", MathFunctionArray("Floor"));
            result.Add("ceiling", MathFunctionArray("Ceiling")); 

            // Type functions.
            signatures = new FunctionDescription[]
            { 
                new FunctionDescription(FunctionNameIsOf, new Type[] { typeof(Type) }, FunctionDescription.UnaryIsOf),
                new FunctionDescription(FunctionNameIsOf, new Type[] { typeof(object), typeof(Type) }, FunctionDescription.BinaryIsOf), 
                new FunctionDescription(FunctionNameIsOf, new Type[] { typeof(ResourceType) }, FunctionDescription.UnaryIsOfResourceType), 
                new FunctionDescription(FunctionNameIsOf, new Type[] { typeof(object), typeof(ResourceType) }, FunctionDescription.BinaryIsOfResourceType),
            }; 
            result.Add(FunctionNameIsOf, signatures);

            // For cast() signatures, we need to add all primitive types directly as well as the object (open type)
            // and unary versions; otherwise expression will convert to object, then again to whatever other type 
            // is required.
            System.Data.Services.Providers.ResourceType[] primitiveTypes = WebUtil.GetPrimitiveTypes(); 
            List castSignatures = new List(primitiveTypes.Length + 4); 
            for (int i = 0; i < primitiveTypes.Length; i++)
            { 
                Debug.Assert(
                    primitiveTypes[i].InstanceType != typeof(Type),
                    "primitiveTypes[i].Type != typeof(Type) -- otherwise extra signatures will be added for cast()");
                Debug.Assert( 
                    primitiveTypes[i].InstanceType != typeof(object),
                    "primitiveTypes[i].Type != typeof(object) -- otherwise extra signatures will be added for cast()"); 
                castSignatures.Add(new FunctionDescription(FunctionNameCast, new Type[] { primitiveTypes[i].InstanceType, typeof(Type) }, FunctionDescription.BinaryCast)); 
            }
 
            castSignatures.Add(new FunctionDescription(FunctionNameCast, new Type[] { typeof(Type) }, FunctionDescription.UnaryCast));
            castSignatures.Add(new FunctionDescription(FunctionNameCast, new Type[] { typeof(object), typeof(Type) }, FunctionDescription.BinaryCast));
            castSignatures.Add(new FunctionDescription(FunctionNameCast, new Type[] { typeof(ResourceType) }, FunctionDescription.UnaryCastResourceType));
            castSignatures.Add(new FunctionDescription(FunctionNameCast, new Type[] { typeof(object), typeof(ResourceType) }, FunctionDescription.BinaryCastResourceType)); 

            result.Add(FunctionNameCast, castSignatures.ToArray()); 
 
            return result;
        } 

        /// Transforms a URI-style "substringof(a,b)" function into "a.contains(b)".
        /// Target of query; not used.
        /// Arguments to function. 
        /// The conversion for this method.
        internal static Expression SubstringOf(Expression target, Expression[] arguments) 
        { 
            Debug.Assert(arguments != null, "arguments != null");
            Debug.Assert(arguments.Length == 2, "arguments.Length == 2"); 

            BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
            Type[] parameterTypes = new Type[] { typeof(string) };
            MethodInfo method = typeof(string).GetMethod("Contains", flags, null, parameterTypes, null); 
            Debug.Assert(method != null, "method != null -- otherwise couldn't find string.Contains(string)");
            return Expression.Call(arguments[1], method, arguments[0]); 
        } 

        /// Performs a type check for the "it" expression. 
        /// "it" expression.
        /// Argument for type check; type.
        /// A new expression with the type check.
        internal static Expression UnaryIsOf(Expression target, Expression[] arguments) 
        {
            ConstantExpression ce = (ConstantExpression)arguments[0]; 
            return Expression.TypeIs(target, (Type)ce.Value); 
        }
 
        /// Performs a type check for a given expression.
        /// "it" expression; unused by this function.
        /// Arguments for type check; instance and type.
        /// A new expression with the type check. 
        internal static Expression BinaryIsOf(Expression target, Expression[] arguments)
        { 
            ConstantExpression ce = (ConstantExpression)arguments[1]; 
            return Expression.TypeIs(arguments[0], (Type)ce.Value);
        } 

        /// Performs a type check for the "it" expression.
        /// "it" expression.
        /// Argument for type check; type. 
        /// A new expression with the type check.
        internal static Expression UnaryIsOfResourceType(Expression target, Expression[] arguments) 
        { 
            Debug.Assert(arguments != null, "arguments != null");
            Debug.Assert(arguments.Length == 1, "arguments.Length == 1"); 
            Debug.Assert(arguments[0].NodeType == ExpressionType.Constant, "Constant expression expected for argument[0]");
            Debug.Assert(((ConstantExpression)arguments[0]).Type == typeof(ResourceType), "Constant expression type should be ResourceType");
            return Expression.Call(null, DataServiceProviderMethods.TypeIsMethodInfo, target, arguments[0]);
        } 

        /// Performs a type check for a given expression. 
        /// "it" expression; unused by this function. 
        /// Arguments for type check; instance and resource type.
        /// A new expression with the type check. 
        internal static Expression BinaryIsOfResourceType(Expression target, Expression[] arguments)
        {
            Debug.Assert(arguments != null, "arguments != null");
            Debug.Assert(arguments.Length == 3, "arguments.Length == 3"); 
            Debug.Assert(arguments[1].NodeType == ExpressionType.Constant, "Constant expression expected for argument[1]");
            Debug.Assert(((ConstantExpression)arguments[1]).Type == typeof(ResourceType), "Constant expression type should be ResourceType"); 
            Debug.Assert(arguments[2].NodeType == ExpressionType.Constant, "Constant expression expected for argument[2]"); 
            Debug.Assert(((ConstantExpression)arguments[2]).Type == typeof(bool), "Constant expression type should be boolean");
 
            bool callOpenTypeMethod = ((bool)((ConstantExpression)arguments[2]).Value) == true;
            return Expression.Call(null, callOpenTypeMethod ? OpenTypeMethods.TypeIsMethodInfo : DataServiceProviderMethods.TypeIsMethodInfo, arguments[0], arguments[1]);
        }
 
        /// Performs a cast for the "it" expression.
        /// "it" expression. 
        /// Argument for cast; type. 
        /// A new expression with the cast.
        internal static Expression UnaryCast(Expression target, Expression[] arguments) 
        {
            Debug.Assert(arguments.Length == 1, "arguments.Length == 1");
            ConstantExpression ce = (ConstantExpression)arguments[0];
            return Expression.Convert(target, (Type)ce.Value); 
        }
 
        /// Performs a cast for a given expression. 
        /// "it" expression; unused by this function.
        /// Arguments for cast; instance and type. 
        /// A new expression with the cast.
        internal static Expression BinaryCast(Expression target, Expression[] arguments)
        {
            Debug.Assert(arguments.Length == 2, "arguments.Length == 2"); 
            ConstantExpression ce = (ConstantExpression)arguments[1];
 
            // Work around for SQLBUDT #615702 - Protocol: exception thrown in XML with filter=null 
            //
            // We need this in place so we can recognize null constant reliably and generate 
            // trees that work for both LINQ to Entities and LINQ to Objects for the cases where
            // conversions of null literals generate expressions that don't guard for nulls in the
            // EF case, but EF ends up calling them anyway because they can be evaluated on the client.
            Type targetType = (Type)ce.Value; 
            if (WebUtil.IsNullConstant(arguments[0]))
            { 
                targetType = WebUtil.GetTypeAllowingNull(targetType); 
                return Expression.Constant(null, targetType);
            } 

            return Expression.Convert(arguments[0], targetType);
        }
 
        /// Performs a cast for the "it" expression.
        /// "it" expression. 
        /// Argument for cast; type. 
        /// A new expression with the cast.
        internal static Expression UnaryCastResourceType(Expression target, Expression[] arguments) 
        {
            Debug.Assert(arguments != null, "arguments != null");
            Debug.Assert(arguments.Length == 1, "arguments.Length == 1");
            Debug.Assert(arguments[0].NodeType == ExpressionType.Constant, "Constant expression expected for argument[0]"); 
            Debug.Assert(((ConstantExpression)arguments[0]).Type == typeof(ResourceType), "Constant expression type should be ResourceType");
            return Expression.Call(null, DataServiceProviderMethods.ConvertMethodInfo, target, arguments[0]); 
        } 

        /// Performs a cast for a given expression. 
        /// "it" expression; unused by this function.
        /// Arguments for cast; instance and type.
        /// A new expression with the cast.
        internal static Expression BinaryCastResourceType(Expression target, Expression[] arguments) 
        {
            Debug.Assert(arguments != null, "arguments != null"); 
            Debug.Assert(arguments.Length == 3, "arguments.Length == 3"); 
            Debug.Assert(arguments[1].NodeType == ExpressionType.Constant, "Constant expression expected for argument[1]");
            Debug.Assert(((ConstantExpression)arguments[1]).Type == typeof(ResourceType), "Constant expression type should be ResourceType"); 
            Debug.Assert(arguments[2].NodeType == ExpressionType.Constant, "Constant expression expected for argument[2]");
            Debug.Assert(((ConstantExpression)arguments[2]).Type == typeof(bool), "Constant expression type should be boolean");

            bool callOpenTypeMethod = ((bool)((ConstantExpression)arguments[2]).Value) == true; 
            return Expression.Call(null, callOpenTypeMethod ? OpenTypeMethods.ConvertMethodInfo : DataServiceProviderMethods.ConvertMethodInfo, arguments[0], arguments[1]);
        } 
 
        /// Creates a new function description for a method or property.
        /// Type on which property or method is declared. 
        /// Whether an instance member is looked for.
        /// Whether a method (rather than a property) is looked for.
        /// Name of member.
        /// Parameter types. 
        /// A new function description.
        private static FunctionDescription CreateFunctionDescription( 
            Type targetType, 
            bool instance,
            bool method, 
            string name,
            params Type[] parameterTypes)
        {
            Debug.Assert(targetType != null, "targetType != null"); 
            Debug.Assert(name != null, "name != null");
            Debug.Assert(parameterTypes.Length == 0 || method, "parameterTypes.Length == 0 || method"); 
            Debug.Assert(method || instance, "method || instance"); 

            BindingFlags flags = BindingFlags.Public | (instance ? BindingFlags.Instance : BindingFlags.Static); 
            MemberInfo member;

            if (method)
            { 
                member = targetType.GetMethod(name, flags, null, parameterTypes, null);
                Debug.Assert(member != null, "methodInfo != null"); 
            } 
            else
            { 
                member = targetType.GetProperty(name, flags);
                Debug.Assert(member != null, "propertyInfo != null");
            }
 
            Type[] functionParameterTypes;
            if (instance) 
            { 
                functionParameterTypes = new Type[parameterTypes.Length + 1];
                functionParameterTypes[0] = targetType; 
                parameterTypes.CopyTo(functionParameterTypes, 1);
            }
            else
            { 
                functionParameterTypes = parameterTypes;
            } 
 
            FunctionDescription result = new FunctionDescription(member, functionParameterTypes);
            if (method) 
            {
                if (instance)
                {
                    result.ConversionFunction = new Func(result.InstanceMethodConversionFunction); 
                }
                else 
                { 
                    result.ConversionFunction = new Func(result.StaticMethodConversionFunction);
                } 
            }
            else
            {
                Debug.Assert(instance, "instance"); 
                result.ConversionFunction = new Func(result.InstancePropertyConversionFunction);
            } 
 
            return result;
        } 

        /// Creates a description for a string instance method.
        /// Name of method to look up.
        /// Parameter types to match. 
        /// A new function description.
        private static FunctionDescription StringInstanceFunction(string name, params Type[] parameterTypes) 
        { 
            return CreateFunctionDescription(typeof(string), true /* instance */, true /* method */, name, parameterTypes);
        } 

        /// Creates an array of function description for a DateTime property.
        /// Name of property to look up.
        /// A new function description array. 
        private static FunctionDescription[] DateTimeFunctionArray(string name)
        { 
            return new FunctionDescription[] 
            {
                CreateFunctionDescription(typeof(DateTime), true /* instance */, false /* method */, name, Type.EmptyTypes) 
            };
        }

        /// Creates an array of function description for math method with decimal and double overloads. 
        /// Name of method to look up.
        /// A new function description array. 
        private static FunctionDescription[] MathFunctionArray(string name) 
        {
            return new FunctionDescription[] 
            {
                CreateFunctionDescription(typeof(Math), false /* instance */, true /* method */, name, typeof(double)),
                CreateFunctionDescription(typeof(Math), false /* instance */, true /* method */, name, typeof(decimal)),
            }; 
        }
    } 
} 

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