예제 #1
0
        /// <summary>Gets a delegate that can be invoked to add an item to a collection of the specified type.</summary>
        /// <param name='listType'>Type of list to use.</param>
        /// <returns>The delegate to invoke.</returns>
        internal static Action <object, object> GetAddToCollectionDelegate(Type listType)
        {
            Debug.Assert(listType != null, "listType != null");

            Type                listElementType;
            MethodInfo          addMethod = ClientTypeUtil.GetAddToCollectionMethod(listType, out listElementType);
            ParameterExpression list      = Expression.Parameter(typeof(object), "list");
            ParameterExpression item      = Expression.Parameter(typeof(object), "element");
            Expression          body      = Expression.Call(Expression.Convert(list, listType), addMethod, Expression.Convert(item, listElementType));

#if ASTORIA_LIGHT
            LambdaExpression lambda = ExpressionHelpers.CreateLambda(body, list, item);
#else
            LambdaExpression lambda = Expression.Lambda(body, list, item);
#endif
            return((Action <object, object>)lambda.Compile());
        }
        internal ClientPropertyAnnotation(IEdmProperty edmProperty, PropertyInfo propertyInfo, DataServiceProtocolVersion maxProtocolVersion)
        {
            ParameterExpression expression;
            ParameterExpression expression2;

            this.EdmProperty          = edmProperty;
            this.PropertyName         = propertyInfo.Name;
            this.NullablePropertyType = propertyInfo.PropertyType;
            this.PropertyType         = Nullable.GetUnderlyingType(this.NullablePropertyType) ?? this.NullablePropertyType;
            this.DeclaringClrType     = propertyInfo.DeclaringType;
            MethodInfo getMethod = propertyInfo.GetGetMethod();
            MethodInfo setMethod = propertyInfo.GetSetMethod();

            this.propertyGetter     = (getMethod == null) ? null : ((Func <object, object>)Expression.Lambda(Expression.Convert(Expression.Call(Expression.Convert(expression = Expression.Parameter(typeof(object), "instance"), this.DeclaringClrType), getMethod), typeof(object)), new ParameterExpression[] { expression }).Compile());
            this.propertySetter     = (setMethod == null) ? null : ((Action <object, object>)Expression.Lambda(Expression.Call(Expression.Convert(expression, this.DeclaringClrType), setMethod, new Expression[] { Expression.Convert(expression2 = Expression.Parameter(typeof(object), "value"), this.NullablePropertyType) }), new ParameterExpression[] { expression, expression2 }).Compile());
            this.MaxProtocolVersion = maxProtocolVersion;
            this.IsKnownType        = PrimitiveType.IsKnownType(this.PropertyType);
            if (!this.IsKnownType)
            {
                MethodInfo method = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(IDictionary <,>), "set_Item", out this.DictionaryValueType);
                if (method != null)
                {
                    ParameterExpression expression3;
                    this.dictionarySetter = (Action <object, string, object>)Expression.Lambda(Expression.Call(Expression.Convert(expression, typeof(IDictionary <,>).MakeGenericType(new Type[] { typeof(string), this.DictionaryValueType })), method, expression3 = Expression.Parameter(typeof(string), "propertyName"), Expression.Convert(expression2, this.DictionaryValueType)), new ParameterExpression[] { expression, expression3, expression2 }).Compile();
                }
                else
                {
                    MethodInfo info4 = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection <>), "Contains", out this.collectionGenericType);
                    MethodInfo addToCollectionMethod = ClientTypeUtil.GetAddToCollectionMethod(this.PropertyType, out this.collectionGenericType);
                    MethodInfo info6 = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection <>), "Remove", out this.collectionGenericType);
                    MethodInfo info7 = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection <>), "Clear", out this.collectionGenericType);
                    this.collectionContains = (info4 == null) ? null : ((Func <object, object, bool>)Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), info4, new Expression[] { Expression.Convert(expression2, this.collectionGenericType) }), new ParameterExpression[] { expression, expression2 }).Compile());
                    this.collectionAdd      = (addToCollectionMethod == null) ? null : ((Action <object, object>)Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), addToCollectionMethod, new Expression[] { Expression.Convert(expression2, this.collectionGenericType) }), new ParameterExpression[] { expression, expression2 }).Compile());
                    this.collectionRemove   = (info6 == null) ? null : ((Func <object, object, bool>)Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), info6, new Expression[] { Expression.Convert(expression2, this.collectionGenericType) }), new ParameterExpression[] { expression, expression2 }).Compile());
                    this.collectionClear    = (info7 == null) ? null : ((Action <object>)Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), info7), new ParameterExpression[] { expression }).Compile());
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Returns MethodInfo instance for a generic type retrieved by using <paramref name="methodName"/> and gets
        /// element type for the provided <paramref name="genericTypeDefinition"/>.
        /// </summary>
        /// <param name="propertyType">starting type</param>
        /// <param name="genericTypeDefinition">the generic type definition to find</param>
        /// <param name="methodName">the method to search for</param>
        /// <param name="type">the element type for <paramref name="genericTypeDefinition" /> if found</param>
        /// <returns>element types</returns>
        internal static MethodInfo GetMethodForGenericType(Type propertyType, Type genericTypeDefinition, string methodName, out Type type)
        {
            Debug.Assert(null != propertyType, "null propertyType");
            Debug.Assert(null != genericTypeDefinition, "null genericTypeDefinition");
            Debug.Assert(genericTypeDefinition.IsGenericTypeDefinition(), "!IsGenericTypeDefinition");

            type = null;

            Type implementationType = ClientTypeUtil.GetImplementationType(propertyType, genericTypeDefinition);

            if (null != implementationType)
            {
                Type[]     genericArguments = implementationType.GetGenericArguments();
                MethodInfo methodInfo       = implementationType.GetMethod(methodName);
                Debug.Assert(null != methodInfo, "should have found the method");

#if DEBUG
                Debug.Assert(null != genericArguments, "null genericArguments");
                ParameterInfo[] parameters = methodInfo.GetParameters();
                if (0 < parameters.Length)
                {
                    // following assert was disabled for Contains which returns bool
                    //// Debug.Assert(typeof(void) == methodInfo.ReturnParameter.ParameterType, "method doesn't return void");

                    Debug.Assert(genericArguments.Length == parameters.Length, "genericArguments don't match parameters");
                    for (int i = 0; i < genericArguments.Length; ++i)
                    {
                        Debug.Assert(genericArguments[i] == parameters[i].ParameterType, "parameter doesn't match generic argument");
                    }
                }
#endif
                type = genericArguments[genericArguments.Length - 1];
                return(methodInfo);
            }

            return(null);
        }
예제 #4
0
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="edmProperty">Back reference to the EdmProperty this annotation is part of.</param>
        /// <param name="propertyInfo">propertyInfo instance.</param>
        /// <param name="backingField">FieldInfo instance for peeking initial property values.</param>
        /// <param name="model">The client model.</param>
        internal ClientPropertyAnnotation(IEdmProperty edmProperty, PropertyInfo propertyInfo, FieldInfo backingField, ClientEdmModel model)
        {
            Debug.Assert(edmProperty != null, "edmProperty != null");
            Debug.Assert(propertyInfo != null, "null propertyInfo");

            // Property should always have DeclaringType
            Debug.Assert(propertyInfo.DeclaringType != null, "Property without a declaring type");

            this.EdmProperty          = edmProperty;
            this.PropertyName         = propertyInfo.Name;
            this.NullablePropertyType = propertyInfo.PropertyType;
            this.PropertyType         = Nullable.GetUnderlyingType(this.NullablePropertyType) ?? this.NullablePropertyType;
            this.DeclaringClrType     = propertyInfo.DeclaringType;

            MethodInfo propertyGetMethod = propertyInfo.GetGetMethod();

            // Add the parameter to make set method is returned even it is not public. Portable lib does not support this.
#if PORTABLELIB
            MethodInfo propertySetMethod = propertyInfo.GetSetMethod();
#else
            MethodInfo propertySetMethod = propertyInfo.GetSetMethod(true);
#endif

            ParameterExpression instance = Expression.Parameter(typeof(Object), "instance");
            ParameterExpression value    = Expression.Parameter(typeof(Object), "value");

            // instance => (Object)(((T)instance).get_PropertyName());  <-- we need to box the value back to object to return
            this.propertyGetter = propertyGetMethod == null ? null : (Func <object, object>)Expression.Lambda(
                Expression.Convert(
                    Expression.Call(
                        Expression.Convert(instance, this.DeclaringClrType),
                        propertyGetMethod),
                    typeof(Object)),
                instance).Compile();

            // (instance, value) => ((T)instance).set_PropertyName((T1)value);
            this.propertySetter = propertySetMethod == null ? null : (Action <object, object>)Expression.Lambda(
                Expression.Call(
                    Expression.Convert(instance, this.DeclaringClrType),
                    propertySetMethod,
                    Expression.Convert(value, this.NullablePropertyType)),
                instance,
                value).Compile();

            if (backingField == null)
            {
                this.fieldOrPropertyGetter = propertyGetter;
            }
            else
            {
                this.fieldOrPropertyGetter = (Func <object, object>)Expression.Lambda(
                    Expression.Convert(
                        Expression.Field(
                            Expression.Convert(instance, this.DeclaringClrType),
                            backingField),
                        typeof(Object)),
                    instance).Compile();
            }

            this.Model = model;

            this.IsKnownType = PrimitiveType.IsKnownType(this.PropertyType);

            // non primitive types: dictionary/collections
            if (!this.IsKnownType)
            {
                var setMethodInfo = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(IDictionary <,>), "set_Item", out this.DictionaryValueType);

                if (setMethodInfo != null)
                {
                    ParameterExpression propertyNameParam = Expression.Parameter(typeof(String), "propertyName");

                    // (instance, propertyName, value) => ((IDictionary<string, DictionaryValueType>)instance)[propertyName] = (DictionaryValueType)value;
                    this.dictionarySetter = (Action <Object, String, Object>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, typeof(IDictionary <,>).MakeGenericType(typeof(String), this.DictionaryValueType)),
                            setMethodInfo,
                            propertyNameParam,
                            Expression.Convert(value, this.DictionaryValueType)),
                        instance,
                        propertyNameParam,
                        value).Compile();
                }
                else
                {
                    var containsMethod = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection <>), "Contains", out this.collectionGenericType);
                    var addMethod      = ClientTypeUtil.GetAddToCollectionMethod(this.PropertyType, out this.collectionGenericType);
                    var removeMethod   = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection <>), "Remove", out this.collectionGenericType);
                    var clearMethod    = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection <>), "Clear", out this.collectionGenericType);

                    // (instance, value) => ((PropertyType)instance).Contains((CollectionType)value);  returns boolean
                    this.collectionContains = containsMethod == null ? null : (Func <Object, Object, Boolean>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            containsMethod,
                            Expression.Convert(value, this.collectionGenericType)),
                        instance,
                        value).Compile();

                    // (instance, value) => ((PropertyType)instance).Add((CollectionType)value);
                    this.collectionAdd = addMethod == null ? null : (Action <Object, Object>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            addMethod,
                            Expression.Convert(value, this.collectionGenericType)),
                        instance,
                        value).Compile();

                    // (instance, value) => ((PropertyType)instance).Remove((CollectionType)value);  returns boolean
                    this.collectionRemove = removeMethod == null ? null : (Func <Object, Object, Boolean>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            removeMethod,
                            Expression.Convert(value, this.collectionGenericType)),
                        instance,
                        value).Compile();

                    // (instance) => ((PropertyType)instance).Clear();
                    this.collectionClear = clearMethod == null ? null : (Action <Object>)Expression.Lambda(
                        Expression.Call(
                            Expression.Convert(instance, this.PropertyType),
                            clearMethod),
                        instance).Compile();
                }
            }

            Debug.Assert(this.collectionGenericType == null || this.DictionaryValueType == null, "collectionGenericType and DictionaryItemType mutually exclusive. (They both can be null though).");
        }
예제 #5
0
        /// <summary>
        /// Returns the list of key properties defined on <paramref name="type"/>; null if <paramref name="type"/> is complex.
        /// </summary>
        /// <param name="type">Type in question.</param>
        /// <param name="hasProperties">true if <paramref name="type"/> has any (declared or inherited) properties; otherwise false.</param>
        /// <returns>Returns the list of key properties defined on <paramref name="type"/>; null if <paramref name="type"/> is complex.</returns>
        internal static PropertyInfo[] GetKeyPropertiesOnType(Type type, out bool hasProperties)
        {
            if (CommonUtil.IsUnsupportedType(type))
            {
                throw new InvalidOperationException(c.Strings.ClientType_UnsupportedType(type));
            }

            string typeName = type.ToString();
            IEnumerable <object> customAttributes = type.GetCustomAttributes(true);
            bool isEntity = customAttributes.OfType <DataServiceEntityAttribute>().Any();
            DataServiceKeyAttribute dataServiceKeyAttribute = customAttributes.OfType <DataServiceKeyAttribute>().FirstOrDefault();
            List <PropertyInfo>     keyProperties           = new List <PropertyInfo>();

            PropertyInfo[] properties = ClientTypeUtil.GetPropertiesOnType(type, false /*declaredOnly*/).ToArray();
            hasProperties = properties.Length > 0;

            KeyKind currentKeyKind = KeyKind.NotKey;
            KeyKind newKeyKind     = KeyKind.NotKey;

            foreach (PropertyInfo propertyInfo in properties)
            {
                if ((newKeyKind = ClientTypeUtil.IsKeyProperty(propertyInfo, dataServiceKeyAttribute)) != KeyKind.NotKey)
                {
                    if (newKeyKind > currentKeyKind)
                    {
                        keyProperties.Clear();
                        currentKeyKind = newKeyKind;
                        keyProperties.Add(propertyInfo);
                    }
                    else if (newKeyKind == currentKeyKind)
                    {
                        keyProperties.Add(propertyInfo);
                    }
                }
            }

            Type keyPropertyDeclaringType = null;

            foreach (PropertyInfo key in keyProperties)
            {
                if (null == keyPropertyDeclaringType)
                {
                    keyPropertyDeclaringType = key.DeclaringType;
                }
                else if (keyPropertyDeclaringType != key.DeclaringType)
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_KeysOnDifferentDeclaredType(typeName));
                }

                if (!PrimitiveType.IsKnownType(key.PropertyType))
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_KeysMustBeSimpleTypes(typeName));
                }
            }

            if (newKeyKind == KeyKind.AttributedKey && keyProperties.Count != dataServiceKeyAttribute.KeyNames.Count)
            {
                var m = (from string a in dataServiceKeyAttribute.KeyNames
                         where null == (from b in properties
                                        where b.Name == a
                                        select b).FirstOrDefault()
                         select a).First <string>();
                throw c.Error.InvalidOperation(c.Strings.ClientType_MissingProperty(typeName, m));
            }

            return(keyProperties.Count > 0 ? keyProperties.ToArray() : (isEntity ? ClientTypeUtil.EmptyPropertyInfoArray : null));
        }
예제 #6
0
 /// <summary>
 /// Is the type or element type (in the case of nullableOfT or IEnumOfT) a Entity Type?
 /// </summary>
 /// <param name="type">Type to examine</param>
 /// <returns>bool indicating whether or not entity type</returns>
 internal static bool TypeOrElementTypeIsEntity(Type type)
 {
     type = TypeSystem.GetElementType(type);
     type = Nullable.GetUnderlyingType(type) ?? type;
     return(!PrimitiveType.IsKnownType(type) && ClientTypeUtil.GetKeyPropertiesOnType(type) != null);
 }
예제 #7
0
 /// <summary>
 /// Gets the Add method to add items to a collection of the specified type.
 /// </summary>
 /// <param name="collectionType">Type for the collection.</param>
 /// <param name="type">The element type in the collection if found; null otherwise.</param>
 /// <returns>The method to invoke to add to a collection of the specified type.</returns>
 internal static MethodInfo GetAddToCollectionMethod(Type collectionType, out Type type)
 {
     return(ClientTypeUtil.GetMethodForGenericType(collectionType, typeof(ICollection <>), "Add", out type));
 }