private void ValidateContract(RelationMetadata metadata, IRelationListContract contract)
        {
            if (contract.ItemType == null)
            {
                this.ThrowContractException(metadata, "Item type cannot be null.");
            }
            else if (string.IsNullOrWhiteSpace(contract.ItemName))
            {
                this.ThrowContractException(metadata, "Item name cannot be empty.");
            }
            else
            {
                Type enumerableType = typeof(IEnumerable <>).MakeGenericType(contract.ItemType);

                if (!enumerableType.IsAssignableFrom(metadata.Type))
                {
                    this.ThrowContractException(metadata, $"List of type '{metadata.Type.GetSanitizedName()}' cannot be converted to '{enumerableType.GetSanitizedName()}'.");
                }
            }

            if (contract.ReadIndex != null && !contract.ReadIndex.HasSignature(contract.ItemType, typeof(int)))
            {
                this.ThrowContractException(metadata, $"ReadIndex method must have signature '{contract.ItemType.GetSanitizedName()} (int)'.");
            }

            if (contract.WriteIndex != null && !contract.WriteIndex.HasSignature(typeof(void), typeof(int), contract.ItemType))
            {
                this.ThrowContractException(metadata, $"WriteIndex method must have signature 'void (int, {contract.ItemType.GetSanitizedName()})'.");
            }
        }
        private IRelationListContract GetListContract(RelationMetadata metadata)
        {
            IEnumerable <IRelationContractResolver> allResolvers = new[] { this.DefaultResolver }.Concat(this);

            IRelationListContract contract = allResolvers.Reverse().NotNull(cr => cr.GetListContract(metadata)).FirstOrDefault();

            if (contract != null)
            {
                this.ValidateContract(metadata, contract);
            }

            return(contract);
        }
        private RelationMetadata CreateItem(IMetadataBuilderContext context, RelationMetadata parent)
        {
            IRelationListContract contract = this.GetListContract(parent);

            if (contract == null)
            {
                return(null);
            }

            MetadataIdentity itemId = parent.Identity.Child(contract.ItemName ?? "Item");

            RelationMetadata metadata = new RelationMetadata(itemId)
            {
                Parent     = parent,
                Type       = contract.ItemType,
                Flags      = RelationMetadataFlags.Item | RelationMetadataFlags.Property,
                ReadIndex  = contract.ReadIndex,
                WriteIndex = contract.WriteIndex,
            };

            metadata.MemberOf    = metadata;
            metadata.Item        = this.CreateItem(context, metadata);
            metadata.Properties  = this.CreateLazy(() => this.CreateProperties(context, metadata));
            metadata.Annotations = this.CreateAnnotations(metadata).ToList();

            if (this.IsMetadataRecursive(metadata))
            {
                metadata.Flags |= RelationMetadataFlags.Recursive;
            }

            if (contract.ReadIndex != null)
            {
                metadata.Flags |= RelationMetadataFlags.Readable;
            }

            if (contract.WriteIndex != null)
            {
                metadata.Flags |= RelationMetadataFlags.Writable;
            }

            if (metadata.Item != null)
            {
                metadata.Flags |= RelationMetadataFlags.List;
            }

            context.AddMetadata <IRelationMetadata>(metadata);

            return(metadata);
        }