Beispiel #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));
            LambdaExpression    lambda    = Expression.Lambda(body, list, item);

            return((Action <object, object>)lambda.Compile());
        }
Beispiel #2
0
        /// <summary>
        /// Get the enum string split by "," with their server side names
        /// </summary>
        /// <param name="enumString">enum string with names in client side</param>
        /// <param name="enumType">the source enum type</param>
        /// <returns>The enum string split by "," with their server side names</returns>
        internal static string GetEnumValuesString(string enumString, Type enumType)
        {
            string[]      enums        = enumString.Split(',').Select(v => v.Trim()).ToArray();
            List <string> memberValues = new List <string>();

            foreach (var enumValue in enums)
            {
                MemberInfo member = enumType.GetField(enumValue);
                if (member == null)
                {
                    throw new NotSupportedException(Strings.Serializer_InvalidEnumMemberValue(enumType.Name, enumValue));
                }

                memberValues.Add(ClientTypeUtil.GetServerDefinedName(member));
            }

            return(string.Join(",", memberValues));
        }
Beispiel #3
0
        /// <summary>
        /// get property wrapper for a property name, might be method around open types for otherwise unknown properties
        /// </summary>
        /// <param name="propertyName">property name</param>
        /// <param name="undeclaredPropertyBehavior">UndeclaredPropertyBehavior</param>
        /// <returns>property wrapper</returns>
        /// <exception cref="InvalidOperationException">for unknown properties on closed types</exception>
        internal ClientPropertyAnnotation GetProperty(string propertyName, UndeclaredPropertyBehavior undeclaredPropertyBehavior)
        {
            Debug.Assert(propertyName != null, "property name");
            if (this.clientPropertyCache == null)
            {
                this.BuildPropertyCache();
            }

            ClientPropertyAnnotation property;

            if (!this.clientPropertyCache.TryGetValue(propertyName, out property))
            {
                string propertyClientName = ClientTypeUtil.GetClientPropertyName(this.ElementType, propertyName, undeclaredPropertyBehavior);
                if ((string.IsNullOrEmpty(propertyClientName) || !this.clientPropertyCache.TryGetValue(propertyClientName, out property)) && (undeclaredPropertyBehavior == UndeclaredPropertyBehavior.ThrowException))
                {
                    throw Microsoft.OData.Client.Error.InvalidOperation(Microsoft.OData.Client.Strings.ClientType_MissingProperty(this.ElementTypeName, propertyName));
                }
            }

            return(property);
        }
Beispiel #4
0
        /// <summary>
        /// get property wrapper for a property name, might be method around open types for otherwise unknown properties
        /// </summary>
        /// <param name="propertyName">property name</param>
        /// <param name="ignoreMissingProperties">are missing properties ignored</param>
        /// <returns>property wrapper</returns>
        /// <exception cref="InvalidOperationException">for unknown properties on closed types</exception>
        internal ClientPropertyAnnotation GetProperty(string propertyName, bool ignoreMissingProperties)
        {
            Debug.Assert(propertyName != null, "property name");
            if (this.clientPropertyCache == null)
            {
                this.BuildPropertyCache();
            }

            ClientPropertyAnnotation property;

            if (!this.clientPropertyCache.TryGetValue(propertyName, out property))
            {
                string propertyClientName = ClientTypeUtil.GetClientPropertyName(this.ElementType, propertyName, ignoreMissingProperties);
                if ((string.IsNullOrEmpty(propertyClientName) || !this.clientPropertyCache.TryGetValue(propertyClientName, out property)) && !ignoreMissingProperties)
                {
                    throw Microsoft.OData.Client.Error.InvalidOperation(Microsoft.OData.Client.Strings.ClientType_MissingProperty(this.ElementTypeName, propertyName));
                }
            }

            return(property);
        }
Beispiel #5
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(propertyType != null, "null propertyType");
            Debug.Assert(genericTypeDefinition != null, "null genericTypeDefinition");
            Debug.Assert(genericTypeDefinition.IsGenericTypeDefinition(), "!IsGenericTypeDefinition");

            type = null;

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

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

#if DEBUG
                Debug.Assert(genericArguments != null, "null genericArguments");
                ParameterInfo[] parameters = methodInfo.GetParameters();
                if (parameters.Length > 0)
                {
                    // 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);
        }
Beispiel #6
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 <EntityTypeAttribute>().Any();
            KeyAttribute        dataServiceKeyAttribute = customAttributes.OfType <KeyAttribute>().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 (keyPropertyDeclaringType == null)
                {
                    keyPropertyDeclaringType = key.DeclaringType;
                }
                else if (keyPropertyDeclaringType != key.DeclaringType)
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_KeysOnDifferentDeclaredType(typeName));
                }

                if (!PrimitiveType.IsKnownType(key.PropertyType) && !(key.PropertyType.GetGenericTypeDefinition() == typeof(System.Nullable <>) && key.PropertyType.GetGenericArguments().First().IsEnum()))
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_KeysMustBeSimpleTypes(key.Name, typeName, key.PropertyType.FullName));
                }
            }

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

            return(keyProperties.Count > 0 ? keyProperties.ToArray() : (isEntity ? ClientTypeUtil.EmptyPropertyInfoArray : null));
        }
Beispiel #7
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);
 }
Beispiel #8
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));
 }
Beispiel #9
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="model">The client model.</param>
        internal ClientPropertyAnnotation(IEdmProperty edmProperty, PropertyInfo propertyInfo, 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         = ClientTypeUtil.GetServerDefinedName(propertyInfo);
            this.NullablePropertyType = propertyInfo.PropertyType;
            this.PropertyType         = Nullable.GetUnderlyingType(this.NullablePropertyType) ?? this.NullablePropertyType;
            this.DeclaringClrType     = propertyInfo.DeclaringType;

            MethodInfo propertyGetMethod = propertyInfo.GetGetMethod();
            MethodInfo propertySetMethod = propertyInfo.GetSetMethod();

            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();

            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).");
        }