public void IFTypeProperty_HasNoKeyAttribute_TypeIsNotEntity() { //Arrange Type student = typeof(Student); //Act bool actualResult = ClientTypeUtil.TypeOrElementTypeIsEntity(student); //Assert Assert.False(actualResult); }
/// <summary> /// Returns true the specified entry represents an entity. /// </summary> /// <param name="entity">The resolved instance</param> /// <param name="model">The client model.</param> /// <returns>True if the entry represents an entity.</returns> private static bool IsEntity(object entity, ClientEdmModel model) { if (entity == null) { // you can set link to null, we need to track these values return(true); } return(ClientTypeUtil.TypeIsEntity(entity.GetType(), model)); }
public void IFTypeProperty_HasKeyAttribute_TypeIsEntity() { //Arrange Type person = typeof(Person); //Act bool actualResult = ClientTypeUtil.TypeOrElementTypeIsEntity(person); //Assert Assert.True(actualResult); }
internal override Expression VisitBinary(BinaryExpression b) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(b.Left.Type) || ClientTypeUtil.TypeOrElementTypeIsEntity(b.Right.Type) || IsCollectionProducingExpression(b.Left) || IsCollectionProducingExpression(b.Right)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, b.ToString())); } return(base.VisitBinary(b)); }
internal override Expression VisitInvocation(InvocationExpression iv) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(iv.Expression.Type) || IsCollectionProducingExpression(iv.Expression) || iv.Arguments.Any(a => ClientTypeUtil.TypeOrElementTypeIsEntity(a.Type) || IsCollectionProducingExpression(a))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, iv.ToString())); } return(base.VisitInvocation(iv)); }
internal override NewExpression VisitNew(NewExpression nex) { // Allow creation of DataServiceCollection<T> objects in projections, stop others that project entities if (ClientTypeUtil.TypeOrElementTypeIsEntity(nex.Type) && !ResourceBinder.PatternRules.MatchNewDataServiceCollectionOfT(nex)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, nex.ToString())); } return(base.VisitNew(nex)); }
private static void Analyze(MemberInitExpression mie, PathBox pb, DataServiceContext context) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(mie.Type)) { EntityProjectionAnalyzer.Analyze(mie, pb, context); } else { NonEntityProjectionAnalyzer.Analyze(mie, pb, context); } }
public void IFTypeProperty_HasKeyAttributeAndOneProperty_TypeIsEntityAndDoesNotThrowException() { //Arrange Type car = typeof(Car); //Act bool actualResult = ClientTypeUtil.TypeOrElementTypeIsEntity(car); //Assert Assert.True(actualResult); }
internal override Expression VisitMemberInit(MemberInitExpression init) { if (!ClientTypeUtil.TypeOrElementTypeIsEntity(init.Type)) { // MemberInit to a complex type is not supported on entity types. throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, init.ToString())); } ProjectionAnalyzer.Analyze(init, this.builder, this.context); return(init); }
/// <summary> /// Reads a value from the message reader. /// </summary> /// <param name="expectedClientType">The expected client type being materialized into.</param> /// <param name="expectedReaderType">The expected type for the underlying reader.</param> protected override void ReadWithExpectedType(IEdmTypeReference expectedClientType, IEdmTypeReference expectedReaderType) { ODataProperty property = this.messageReader.ReadProperty(expectedReaderType); Type underlyingExpectedType = Nullable.GetUnderlyingType(this.ExpectedType) ?? this.ExpectedType; object propertyValue = property.Value; if (expectedClientType.IsCollection()) { Debug.Assert(WebUtil.IsCLRTypeCollection(underlyingExpectedType, this.MaterializerContext.Model) || (SingleResult.HasValue && !SingleResult.Value), "expected type must be collection or single result must be false"); // We are here for two cases: // (1) Something like Execute<ICollection<T>>, in which case the underlyingExpectedType is ICollection<T> // (2) Execute<T> with the bool singleValue = false, in which case underlyingExpectedType is T Type collectionItemType = underlyingExpectedType; Type collectionICollectionType = ClientTypeUtil.GetImplementationType(underlyingExpectedType, typeof(ICollection <>)); object collectionInstance; if (collectionICollectionType != null) { // Case 1 collectionItemType = collectionICollectionType.GetGenericArguments()[0]; collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, underlyingExpectedType); } else { // Case 2 collectionICollectionType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType }); collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, collectionICollectionType); } this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues( property, collectionInstance, collectionItemType, ClientTypeUtil.GetAddToCollectionDelegate(collectionICollectionType)); this.currentValue = collectionInstance; } else if (expectedClientType.IsComplex()) { ODataComplexValue complexValue = propertyValue as ODataComplexValue; Debug.Assert(this.MaterializerContext.Model.GetOrCreateEdmType(underlyingExpectedType).ToEdmTypeReference(false).IsComplex(), "expectedType must be complex type"); this.ComplexValueMaterializationPolicy.MaterializeComplexTypeProperty(underlyingExpectedType, complexValue); this.currentValue = complexValue.GetMaterializedValue(); } else { Debug.Assert(this.MaterializerContext.Model.GetOrCreateEdmType(underlyingExpectedType).ToEdmTypeReference(false).IsPrimitive(), "expectedType must be primitive type"); this.currentValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(property.Value, this.ExpectedType); } }
internal void EnterLambdaScope(LambdaExpression lambda, Expression entry, Expression expectedType) { ParameterExpression item = lambda.Parameters[0]; Type type = lambda.Body.Type; bool flag = ClientTypeUtil.TypeOrElementTypeIsEntity(type); this.entityInScope.Push(flag); this.parameterExpressions.Push(item); this.parameterExpressionTypes.Push(expectedType); this.parameterEntries.Push(entry); this.parameterProjectionTypes.Push(type); }
internal override Expression VisitParameter(ParameterExpression p) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(p.Type)) { if (p != this.box.ParamExpressionInScope) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, p.ToString())); } this.box.StartNewPath(); } return(p); }
/// <summary> /// ConstantExpression visit method /// </summary> /// <param name="c">The ConstantExpression expression to visit</param> /// <returns>The visited ConstantExpression expression </returns> internal override Expression VisitConstant(ConstantExpression c) { if (c.Value == null) { this.builder.Append(UriHelper.NULL); return(c); } // DEVNOTE: // Rather than forcing every other codepath to have the 'Try...' pattern for formatting, // we catch the InvalidOperationException here to change the exception type. // This is exceedingly rare, and not a scenario where performance is meaningful, so the // reduced complexity in all other call sites is worth the extra logic here. string result; BinaryExpression b = this.parent as BinaryExpression; MethodCallExpression m = this.parent as MethodCallExpression; if ((b != null && HasEnumInBinaryExpression(b)) || (m != null && m.Method.Name == "HasFlag")) { c = this.ConvertConstantExpressionForEnum(c); ClientEdmModel model = this.context.Model; IEdmType edmType = model.GetOrCreateEdmType(c.Type.IsEnum() ? c.Type : c.Type.GetGenericArguments()[0]); ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType); string typeNameInEdm = this.context.ResolveNameFromTypeInternal(typeAnnotation.ElementType); MemberInfo member = typeAnnotation.ElementType.GetField(c.Value.ToString()); string memberValue = ClientTypeUtil.GetServerDefinedName(member); ODataEnumValue enumValue = new ODataEnumValue(memberValue, typeNameInEdm ?? typeAnnotation.ElementTypeName); result = ODataUriUtils.ConvertToUriLiteral(enumValue, CommonUtil.ConvertToODataVersion(this.uriVersion), null); } else { try { result = LiteralFormatter.ForConstants.Format(c.Value); } catch (InvalidOperationException) { if (this.cantTranslateExpression) { // there's already a problem in the parents. // we should just return here, because caller somewhere up the stack will throw a better exception return(c); } throw new NotSupportedException(Strings.ALinq_CouldNotConvert(c.Value)); } } Debug.Assert(result != null, "result != null"); this.builder.Append(result); return(c); }
public void ShouldMaterializeTimeOfDayCollection() { var primitiveValues = new List <TimeOfDay>(new TimeOfDay[] { TimeOfDay.MinValue, new TimeOfDay(19, 9, 28, 123), TimeOfDay.MaxValue }); var outputCollection = new List <TimeOfDay>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( primitiveValues, "Edm.TimeOfDay", outputCollection, typeof(TimeOfDay), addToDelegate, false); outputCollection.Should().HaveCount(3); outputCollection[0].Should().Be(TimeOfDay.MinValue); outputCollection[1].Should().Be(new TimeOfDay(19, 9, 28, 123)); outputCollection[2].Should().Be(TimeOfDay.MaxValue); }
/// <summary>Initializes a new <see cref="ProjectionPathSegment"/> instance.</summary> /// <param name="startPath">Path on which this segment is located.</param> /// <param name="memberExpression">Member expression for the projection path; possibly null.</param> internal ProjectionPathSegment(ProjectionPath startPath, MemberExpression memberExpression) { Debug.Assert(startPath != null, "startPath != null"); Debug.Assert(memberExpression != null, "memberExpression != null"); this.StartPath = startPath; Expression source = ResourceBinder.StripTo <Expression>(memberExpression.Expression); this.Member = ClientTypeUtil.GetServerDefinedName(memberExpression.Member); this.ProjectionType = memberExpression.Type; this.SourceTypeAs = source.NodeType == ExpressionType.TypeAs ? source.Type : null; }
/// <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()); }
public void ShouldMaterializeNullableIntCollection() { var primitiveValues = new List <int?>(new int?[] { 1, null, 10 }); var outputCollection = new List <int?>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( primitiveValues, "Edm.Int32", outputCollection, typeof(int?), addToDelegate, true); outputCollection.Should().HaveCount(3); outputCollection[0].Should().Be(1); outputCollection[1].Should().Be(null); outputCollection[2].Should().Be(10); }
internal static string GetEntityTypeNameForUriAndValidateMaxProtocolVersion(Type type, DataServiceContext context, ref Version uriVersion) { if (context.MaxProtocolVersionAsVersion < Util.DataServiceVersion3) { throw new NotSupportedException(Strings.ALinq_TypeAsNotSupportedForMaxDataServiceVersionLessThan3); } if (!ClientTypeUtil.TypeOrElementTypeIsEntity(type)) { throw new NotSupportedException(Strings.ALinq_TypeAsArgumentNotEntityType(type.FullName)); } WebUtil.RaiseVersion(ref uriVersion, Util.DataServiceVersion3); return(context.ResolveNameFromType(type) ?? type.FullName); }
public void ShouldMaterializeDateCollection() { var primitiveValues = new List <Date>(new Date[] { Date.MinValue, new Date(2014, 9, 28), Date.MaxValue }); var outputCollection = new List <Date>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( primitiveValues, "Edm.Date", outputCollection, typeof(Date), addToDelegate, false); outputCollection.Should().HaveCount(3); outputCollection[0].Should().Be(Date.MinValue); outputCollection[1].Should().Be(new Date(2014, 9, 28)); outputCollection[2].Should().Be(Date.MaxValue); }
/// <summary> /// Checks whether the specified expression is allowed in a MethodCall. Expressions that /// produce collections are not allowed. The only exception is when collection property /// belongs to an entity e.g. c.Orders.Select(o => o), where we allow c.Orders. /// </summary> /// <param name="e">Expression to check.</param> /// <param name="model">The client model used.</param> /// <returns>true if expression is disallowed, false otherwise.</returns> internal static bool IsDisallowedExpressionForMethodCall(Expression e, ClientEdmModel model) { // If this is a collection hanging off a Entity, then that is fine. MemberExpression me = e as MemberExpression; if (me != null && ClientTypeUtil.TypeIsEntity(me.Expression.Type, model)) { return(false); } // All collection producing expressions are disallowed. return(IsCollectionProducingExpression(e)); }
/// <summary> /// Determine if the specified type is an entity type. /// </summary> /// <param name="type">An object type specifier.</param> /// <param name="model">The client model.</param> /// <returns>true if the type is an entity type; otherwise false.</returns> internal static bool IsEntityType(Type type, ClientEdmModel model) { Debug.Assert(type != null, "Argument 'type' cannot be null."); metadataCacheLock.EnterReadLock(); try { if (knownNonEntityTypes.Contains(type)) { return(false); } } finally { metadataCacheLock.ExitReadLock(); } bool isEntityType; try { if (BindingEntityInfo.IsDataServiceCollection(type, model)) { return(false); } isEntityType = ClientTypeUtil.TypeOrElementTypeIsEntity(type); } catch (InvalidOperationException) { isEntityType = false; } if (!isEntityType) { metadataCacheLock.EnterWriteLock(); try { if (!knownNonEntityTypes.Contains(type)) { knownNonEntityTypes.Add(type); } } finally { metadataCacheLock.ExitWriteLock(); } } return(isEntityType); }
/// <summary> /// Resolves the client type that should be used for materialization. /// </summary> /// <param name="expectedType">Expected client clr type based on the API called.</param> /// <param name="readerTypeName"> /// The name surfaced by the ODataLib reader. /// If we have a server model, this will be a server type name that needs to be resolved. /// If not, then this will already be a client type name.</param> /// <returns>The resolved annotation for the client type to materialize into.</returns> internal ClientTypeAnnotation ResolveTypeForMaterialization(Type expectedType, string readerTypeName) { // If its a collection, get the collection item name string collectionItemTypeName = WebUtil.GetCollectionItemWireTypeName(readerTypeName); if (collectionItemTypeName == null) { // Resolve the primitive type first PrimitiveType primitiveType; if (PrimitiveType.TryGetPrimitiveType(readerTypeName, out primitiveType)) { return(this.clientEdmModel.GetClientTypeAnnotation(primitiveType.ClrType)); } ClientTypeAnnotation resultType; if (this.edmTypeNameMap.TryGetValue(readerTypeName, out resultType)) { return(resultType); } if (this.serviceModel != null) { var resolvedType = this.ResolveTypeFromName(readerTypeName, expectedType); return(this.clientEdmModel.GetClientTypeAnnotation(resolvedType)); } // If there was no type name specified in the payload, then the type resolver won't be invoked // and hence that edm type name might not be in the resolver cache. Hence look that up in the // ClientEdmModel cache. This lookup is more expensive and is unique across the app domain for the // given version. return(this.clientEdmModel.GetClientTypeAnnotation(readerTypeName)); } Type collectionImplementationType = ClientTypeUtil.GetImplementationType(expectedType, typeof(ICollection <>)); Type collectionElementType = collectionImplementationType.GetGenericArguments()[0]; // In case of collection, the expectedType might be collection of nullable types (for e.g. ICollection<int?>). // There is no way to know the nullability from the wireTypeName (For e.g. Collection(Edm.Int32)). // Hence in case of collections of primitives, we need to look at the element type of the expected type // and use that to create the instance otherwise we will not be able to assign the created ICollection<> // instance to the property on the user's entity (ICollection<int> cannot be assigned to ICollection<int?>). // There is also no need to invoke the resolver for primitives, so we just use the element type. if (!PrimitiveType.IsKnownType(collectionElementType)) { collectionElementType = this.ResolveTypeForMaterialization(collectionElementType, collectionItemTypeName).ElementType; } Type clrCollectionType = WebUtil.GetBackingTypeForCollectionProperty(expectedType); return(this.clientEdmModel.GetClientTypeAnnotation(clrCollectionType)); }
internal override Expression VisitInvocation(InvocationExpression iv) { if ((ClientTypeUtil.TypeOrElementTypeIsEntity(iv.Expression.Type) || ProjectionAnalyzer.IsCollectionProducingExpression(iv.Expression)) || iv.Arguments.Any <Expression>(delegate(Expression a) { if (!ClientTypeUtil.TypeOrElementTypeIsEntity(a.Type)) { return(ProjectionAnalyzer.IsCollectionProducingExpression(a)); } return(true); })) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, iv.ToString())); } return(base.VisitInvocation(iv)); }
internal override Expression VisitConditional(ConditionalExpression c) { ResourceBinder.PatternRules.MatchNullCheckResult result = ResourceBinder.PatternRules.MatchNullCheck(this.box.ParamExpressionInScope, c); if (result.Match) { this.Visit(result.AssignExpression); return(c); } if (((ClientTypeUtil.TypeOrElementTypeIsEntity(c.Test.Type) || ClientTypeUtil.TypeOrElementTypeIsEntity(c.IfTrue.Type)) || (ClientTypeUtil.TypeOrElementTypeIsEntity(c.IfFalse.Type) || ProjectionAnalyzer.IsCollectionProducingExpression(c.Test))) || (ProjectionAnalyzer.IsCollectionProducingExpression(c.IfTrue) || ProjectionAnalyzer.IsCollectionProducingExpression(c.IfFalse))) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, c.ToString())); } return(base.VisitConditional(c)); }
/// <summary> /// Creates an Edm property. /// </summary> /// <param name="declaringType">Type declaring this property.</param> /// <param name="propertyInfo">PropertyInfo instance for this property.</param> /// <returns>Returns a new instance of Edm property.</returns> private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo) { IEdmType propertyEdmType = this.GetOrCreateEdmType(propertyInfo.PropertyType); Debug.Assert( propertyEdmType.TypeKind == EdmTypeKind.Entity || propertyEdmType.TypeKind == EdmTypeKind.Complex || propertyEdmType.TypeKind == EdmTypeKind.Enum || propertyEdmType.TypeKind == EdmTypeKind.Primitive || propertyEdmType.TypeKind == EdmTypeKind.Collection, "Property kind should be Entity, Complex, Enum, Primitive or Collection."); IEdmProperty edmProperty = null; bool isPropertyNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType); if (propertyEdmType.TypeKind == EdmTypeKind.Entity || (propertyEdmType.TypeKind == EdmTypeKind.Collection && ((IEdmCollectionType)propertyEdmType).ElementType.TypeKind() == EdmTypeKind.Entity)) { if (declaringType.TypeKind == EdmTypeKind.Entity || declaringType.TypeKind == EdmTypeKind.Complex) { if (declaringType as IEdmEntityType == null && declaringType as IEdmComplexType == null) { throw c.Error.InvalidOperation(c.Strings.ClientTypeCache_NonEntityTypeOrNonComplexTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString())); } // Create a navigation property representing one side of an association. // The partner representing the other side exists only inside this property and is not added to the target entity type, // so it should not cause any name collisions. edmProperty = EdmNavigationProperty.CreateNavigationPropertyWithPartner( ClientTypeUtil.GetServerDefinedName(propertyInfo), propertyEdmType.ToEdmTypeReference(isPropertyNullable), /*dependentProperties*/ null, /*principalProperties*/ null, /*containsTarget*/ false, EdmOnDeleteAction.None, "Partner", declaringType.ToEdmTypeReference(true), /*partnerDependentProperties*/ null, /*partnerPrincipalProperties*/ null, /*partnerContainsTarget*/ false, EdmOnDeleteAction.None); } } else { edmProperty = new EdmStructuralProperty(declaringType, ClientTypeUtil.GetServerDefinedName(propertyInfo), propertyEdmType.ToEdmTypeReference(isPropertyNullable)); } edmProperty.SetClientPropertyAnnotation(new ClientPropertyAnnotation(edmProperty, propertyInfo, this)); return(edmProperty); }
public void AddingCollectionToPrimitiveCollectionShouldFail() { var collectionValues = new List <object>(new object[] { new ODataCollectionValue() }); var outputCollection = new List <int>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); Action test = () => this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( collectionValues, "Edm.Int32", outputCollection, typeof(int), addToDelegate, false); test.ShouldThrow <InvalidOperationException>(DSClient.Strings.Collection_CollectionTypesInCollectionOfPrimitiveTypesNotAllowed); }
public void AddingPrimitiveValueToComplexCollectionShouldFail() { var primitiveValues = new List <object>(new object[] { 1 }); var outputCollection = new List <Point>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); Action test = () => this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( primitiveValues, "Point", outputCollection, typeof(Point), addToDelegate, false); test.ShouldThrow <InvalidOperationException>(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); }
[TestMethod] public void NullComplexValueShouldFail() { var primitiveValues = new List <ODataComplexValue>(new ODataComplexValue[] { null }); var outputCollection = new List <Point>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); Action test = () => this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( primitiveValues, "Point", outputCollection, typeof(Point), addToDelegate, false); test.ShouldThrow <InvalidOperationException>().WithMessage(DSClient.Strings.Collection_NullCollectionItemsNotSupported); }
/// <summary> /// Reads a value from the message reader. /// </summary> /// <param name="expectedClientType">The expected client type being materialized into.</param> /// <param name="expectedReaderType">The expected type for the underlying reader.</param> protected override void ReadWithExpectedType(IEdmTypeReference expectedClientType, IEdmTypeReference expectedReaderType) { if (!expectedClientType.IsCollection()) { throw new DataServiceClientException(DSClient.Strings.AtomMaterializer_TypeShouldBeCollectionError(expectedClientType.FullName())); } Type underlyingExpectedType = Nullable.GetUnderlyingType(this.ExpectedType) ?? this.ExpectedType; Debug.Assert(WebUtil.IsCLRTypeCollection(underlyingExpectedType, this.MaterializerContext.Model) || (SingleResult.HasValue && !SingleResult.Value), "expected type must be collection or single result must be false"); // We are here for two cases: // (1) Something like Execute<ICollection<T>>, in which case the underlyingExpectedType is ICollection<T> // (2) Execute<T> with the bool singleValue = false, in which case underlyingExpectedType is T Type collectionItemType = underlyingExpectedType; Type collectionICollectionType = ClientTypeUtil.GetImplementationType(underlyingExpectedType, typeof(ICollection <>)); if (collectionICollectionType != null) { // Case 1 : Something like Execute<ICollection<T>>, in which case the underlyingExpectedType is ICollection<T> collectionItemType = collectionICollectionType.GetGenericArguments()[0]; } else { // Case 2 : Execute<T> with the bool singleValue = false, in which case underlyingExpectedType is T collectionICollectionType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType }); } Type clrCollectionType = WebUtil.GetBackingTypeForCollectionProperty(collectionICollectionType); object collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionInstance((IEdmCollectionTypeReference)expectedClientType, clrCollectionType); // Enumerator over our collection reader was created, then ApplyDataCollections was refactored to // take an enumerable instead of a ODataCollectionValue. Enumerator is being used as a bridge ODataCollectionReader collectionReader = messageReader.CreateODataCollectionReader(); NonEntityItemsEnumerable collectionEnumerable = new NonEntityItemsEnumerable(collectionReader); bool isElementNullable = expectedClientType.AsCollection().ElementType().IsNullable; this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues( collectionEnumerable, null /*wireTypeName*/, collectionInstance, collectionItemType, ClientTypeUtil.GetAddToCollectionDelegate(collectionICollectionType), isElementNullable); this.currentValue = collectionInstance; }
public void ShouldMaterializeComplexCollection() { var primitiveValues = new List <ODataComplexValue>(new ODataComplexValue[] { new ODataComplexValue() { Properties = new ODataProperty[] { new ODataProperty() { Name = "X", Value = 15 }, new ODataProperty() { Name = "Y", Value = 18 } } }, new ODataComplexValue() { Properties = new ODataProperty[] { new ODataProperty() { Name = "X", Value = 22 }, new ODataProperty() { Name = "Y", Value = 25 } } }, new ODataComplexValue() { Properties = new ODataProperty[] { new ODataProperty() { Name = "X", Value = -100 }, new ODataProperty() { Name = "Y", Value = -201 } } }, }); var outputCollection = new List <Point>(); var addToDelegate = ClientTypeUtil.GetAddToCollectionDelegate(outputCollection.GetType()); this.CreateCollectionValueMaterializationPolicy().ApplyCollectionDataValues( primitiveValues, "Point", outputCollection, typeof(Point), addToDelegate, false); outputCollection.Should().HaveCount(3); outputCollection[0].X.Should().Be(15); outputCollection[0].Y.Should().Be(18); outputCollection[1].X.Should().Be(22); outputCollection[1].Y.Should().Be(25); outputCollection[2].X.Should().Be(-100); outputCollection[2].Y.Should().Be(-201); }