TypeUsage.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Metadata / Edm / TypeUsage.cs / 1305376 / TypeUsage.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization; 
using System.Text;
using System.Data.Common.Utils; 
using System.Linq; 

namespace System.Data.Metadata.Edm 
{
    /// 
    /// Class representing a type information for an item
    ///  
    [DebuggerDisplay("EdmType={EdmType}, Facets.Count={Facets.Count}")]
    public sealed class TypeUsage : MetadataItem 
    { 
        #region Constructors
 
        /// 
        /// The constructor for TypeUsage taking in a type
        /// 
        /// The type which the TypeUsage object describes 
        /// Thrown if edmType argument is null
        private TypeUsage(EdmType edmType) 
        :base(MetadataFlags.Readonly) 
        {
            EntityUtil.GenericCheckArgumentNull(edmType, "edmType"); 

            _edmType = edmType;

            // I would like to be able to assert that the edmType is ReadOnly, but 
            // because some types are still in loading while the TypeUsage is being created
            // that won't work. We should consider a way to change this 
        } 

        ///  
        /// The constructor for TypeUsage taking in a type and a collection of facets
        /// 
        /// The type which the TypeUsage object describes
        /// The replacement collection of facets 
        /// Thrown if edmType argument is null
        private TypeUsage(EdmType edmType, IEnumerable facets) 
            : this(edmType) 
        {
            MetadataCollection facetCollection = new MetadataCollection(facets); 
            facetCollection.SetReadOnly();
            _facets = facetCollection.AsReadOnlyMetadataCollection();
        }
        #endregion 

        #region Factory Methods 
        ///  
        /// Factory method for creating a TypeUsage with specified EdmType
        ///  
        /// EdmType for which to create a type usage
        /// new TypeUsage instance with default facet values
        internal static TypeUsage Create(EdmType edmType)
        { 
            return new TypeUsage(edmType);
        } 
 
        /// 
        /// Factory method for creating a TypeUsage with specified EdmType 
        /// 
        /// EdmType for which to create a type usage
        /// new TypeUsage instance with default facet values
        internal static TypeUsage Create(EdmType edmType, FacetValues values) 
        {
            return new TypeUsage(edmType, 
                GetDefaultFacetDescriptionsAndOverrideFacetValues(edmType, values)); 
        }
 
        /// 
        /// Factory method for creating a TypeUsage with specified EdmType and facets
        /// 
        /// EdmType for which to create a type usage 
        /// facets to be copied into the new TypeUsage
        /// new TypeUsage instance 
        internal static TypeUsage Create(EdmType edmType, IEnumerable facets) 
        {
            return new TypeUsage(edmType, facets); 
        }

        internal TypeUsage ShallowCopy(FacetValues facetValues)
        { 
            return TypeUsage.Create(_edmType, OverrideFacetValues(Facets, facetValues));
        } 
 
        /// 
        /// Factory method for creating a "readonly" TypeUsage with specified EdmType 
        /// 
        /// An EdmType for which to create a TypeUsage
        /// A TypeUsage instance with default facet values for the specified EdmType
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "0#edm")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
        public static TypeUsage CreateDefaultTypeUsage(EdmType edmType) 
        { 
            EntityUtil.CheckArgumentNull(edmType, "edmType");
 
            TypeUsage type = TypeUsage.Create(edmType);
            return type;
        }
 
        /// 
        /// Factory method for creating a string TypeUsage object with the specified facets 
        ///  
        /// A PrimitiveType for which to construct the TypeUsage
        /// Whether the string type is unicode or not 
        /// Whether the string type is fixed length or not
        /// The max length of the string type
        /// A TypeUsage object describing a string type with the given facet values
        public static TypeUsage CreateStringTypeUsage(PrimitiveType primitiveType, 
                                                      bool isUnicode,
                                                      bool isFixedLength, 
                                                      int maxLength) 
        {
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.String)
            {
                throw EntityUtil.NotStringTypeForTypeUsage(); 
            }
 
            ValidateMaxLength(maxLength); 

            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ MaxLength = maxLength, Unicode = isUnicode, FixedLength = isFixedLength});

            return typeUsage;
        } 

        ///  
        /// Factory method for creating a string TypeUsage object with the specified facets and 
        /// unbounded MaxLength
        ///  
        /// A PrimitiveType for which to construct the TypeUsage
        /// Whether the string type is unicode or not
        /// Whether the string type is fixed length or not
        /// A TypeUsage object describing a string type with the given facet values 
        /// and unbounded MaxLength
        public static TypeUsage CreateStringTypeUsage(PrimitiveType primitiveType, 
                                                      bool isUnicode, 
                                                      bool isFixedLength)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.String)
            { 
                throw EntityUtil.NotStringTypeForTypeUsage();
            } 
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ MaxLength = TypeUsage.DefaultMaxLengthFacetValue,
                                  Unicode = isUnicode, FixedLength = isFixedLength}); 

            return typeUsage;
        }
 

        ///  
        /// Factory method for creating a Binary TypeUsage object with the specified facets 
        /// 
        /// A PrimitiveType for which to construct TypeUsage 
        /// Whether the binary type is fixed length or not
        /// The max length of the binary type
        /// A TypeUsage object describing a binary type with the given facet values
        public static TypeUsage CreateBinaryTypeUsage(PrimitiveType primitiveType, 
                                                      bool isFixedLength,
                                                      int maxLength) 
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Binary)
            {
                throw EntityUtil.NotBinaryTypeForTypeUsage();
            } 

            ValidateMaxLength(maxLength); 
 
            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{MaxLength = maxLength, FixedLength = isFixedLength}); 

            return typeUsage;
        }
 
        /// 
        /// Factory method for creating a Binary TypeUsage object with the specified facets and 
        /// unbounded MaxLength 
        /// 
        /// A PrimitiveType for which to construct the TypeUsage 
        /// Whether the binary type is fixed length or not
        /// A TypeUsage object describing a binary type with the given facet values
        public static TypeUsage CreateBinaryTypeUsage(PrimitiveType primitiveType, bool isFixedLength)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Binary) 
            {
                throw EntityUtil.NotBinaryTypeForTypeUsage(); 
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{MaxLength = TypeUsage.DefaultMaxLengthFacetValue,
                                 FixedLength = isFixedLength}); 

            return typeUsage; 
        } 

        ///  
        /// Factory method for creating a DateTime TypeUsage object with the specified facets
        /// 
        /// A PrimitiveType for which to construct the TypeUsage
        /// Precision for seconds 
        /// A TypeUsage object describing a DateTime type with the given facet values
        public static TypeUsage CreateDateTimeTypeUsage(PrimitiveType primitiveType, 
                                                        byte? precision) 
        {
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.DateTime)
            {
                throw EntityUtil.NotDateTimeTypeForTypeUsage(); 
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{Precision = precision}); 

            return typeUsage; 
        }

        /// 
        /// Factory method for creating a DateTimeOffset TypeUsage object with the specified facets 
        /// 
        /// A PrimitiveType for which to construct the TypeUsage 
        /// Precision for seconds 
        /// A TypeUsage object describing a DateTime type with the given facet values
        public static TypeUsage CreateDateTimeOffsetTypeUsage(PrimitiveType primitiveType, 
                                                        byte? precision)
        {
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.DateTimeOffset)
            { 
                throw EntityUtil.NotDateTimeOffsetTypeForTypeUsage(); 
            }
 
            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{ Precision = precision });

            return typeUsage; 
        }
 
        ///  
        /// Factory method for creating a Time TypeUsage object with the specified facets
        ///  
        /// A PrimitiveType for which to construct the TypeUsage
        /// Precision for seconds
        /// A TypeUsage object describing a Time type with the given facet values
        public static TypeUsage CreateTimeTypeUsage(PrimitiveType primitiveType, 
                                                        byte? precision)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Time) 
            {
                throw EntityUtil.NotTimeTypeForTypeUsage();
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ Precision = precision });
 
            return typeUsage; 
        }
 


        /// 
        /// Factory method for creating a Decimal TypeUsage object with the specified facets 
        /// 
        /// A PrimitiveType for which to construct type usage 
        /// The precision of the decimal type 
        /// The scale of the decimal type
        /// A TypeUsage object describing a decimal type with the given facet values 
        public static TypeUsage CreateDecimalTypeUsage(PrimitiveType primitiveType,
                                                       byte precision,
                                                       byte scale)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal) 
            {
                throw EntityUtil.NotDecimalTypeForTypeUsage(); 
            }

            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{Precision = precision, Scale = scale }); 

            return typeUsage; 
        } 

        ///  
        /// Factory method for creating a Decimal TypeUsage object with unbounded precision and scale
        /// 
        /// The PrimitiveType for which to construct type usage
        /// A TypeUsage object describing a decimal type with unbounded precision and scale 
        public static TypeUsage CreateDecimalTypeUsage(PrimitiveType primitiveType)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal) 
            {
                throw EntityUtil.NotDecimalTypeForTypeUsage();
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ Precision = TypeUsage.DefaultPrecisionFacetValue, Scale = TypeUsage.DefaultScaleFacetValue });
 
            return typeUsage; 
        }
        #endregion 

        #region Fields
        private TypeUsage _modelTypeUsage;
        private readonly EdmType _edmType; 
        private ReadOnlyMetadataCollection _facets;
        private string _identity; 
 
        /// 
        /// Set of facets that should be included in identity for TypeUsage 
        /// 
        /// keep this sorted for binary searching
        private static readonly string[] s_identityFacets = new string[] {
            DbProviderManifest.DefaultValueFacetName, 
            DbProviderManifest.FixedLengthFacetName,
            DbProviderManifest.MaxLengthFacetName, 
            DbProviderManifest.NullableFacetName, 
            DbProviderManifest.PrecisionFacetName,
            DbProviderManifest.ScaleFacetName, 
            DbProviderManifest.UnicodeFacetName,
        };

        internal static readonly EdmConstants.Unbounded DefaultMaxLengthFacetValue       = EdmConstants.UnboundedValue; 
        internal static readonly EdmConstants.Unbounded DefaultPrecisionFacetValue       = EdmConstants.UnboundedValue;
        internal static readonly EdmConstants.Unbounded DefaultScaleFacetValue           = EdmConstants.UnboundedValue; 
        internal static readonly bool                   DefaultUnicodeFacetValue         = true; 
        internal static readonly bool                   DefaultFixedLengthFacetValue     = false;
        internal static readonly byte?                   DefaultDateTimePrecisionFacetValue = null; 

        #endregion

        #region Properties 
        /// 
        /// Returns the kind of the type 
        ///  
        public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.TypeUsage; } }
 
        /// 
        /// Gets the type that this TypeUsage describes
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")] 
        [MetadataProperty(BuiltInTypeKind.EdmType, false)]
        public EdmType EdmType 
        { 
            get
            { 
                return _edmType;
            }
        }
 
        /// 
        /// Gets the list of facets for the type in this TypeUsage 
        ///  
        [MetadataProperty(BuiltInTypeKind.Facet, true)]
        public ReadOnlyMetadataCollection Facets 
        {
            get
            {
                if (null == _facets) 
                {
                    MetadataCollection facets = new MetadataCollection(GetFacets()); 
                    // we never modify the collection so we can set it readonly from the start 
                    facets.SetReadOnly();
                    System.Threading.Interlocked.CompareExchange(ref _facets, facets.AsReadOnlyMetadataCollection(), null); 
                }
                return _facets;
            }
        } 
        #endregion
 
        #region Methods 
        /// 
        /// Returns a Model type usage for a provider type 
        /// 
        /// model (CSpace) type usage
        internal TypeUsage GetModelTypeUsage()
        { 
            if (_modelTypeUsage == null)
            { 
                EdmType edmType = this.EdmType; 

                // If the edm type is already a cspace type, return the same type 
                if (edmType.DataSpace == DataSpace.CSpace || edmType.DataSpace == DataSpace.OSpace)
                {
                    return this;
                } 

                TypeUsage result; 
                if (Helper.IsRowType(edmType)) 
                {
                    RowType sspaceRowType = (RowType)edmType; 
                    EdmProperty[] properties = new EdmProperty[sspaceRowType.Properties.Count];
                    for (int i = 0; i < properties.Length; i++)
                    {
                        EdmProperty sspaceProperty = sspaceRowType.Properties[i]; 
                        TypeUsage newTypeUsage = sspaceProperty.TypeUsage.GetModelTypeUsage();
                        properties[i] = new EdmProperty(sspaceProperty.Name, newTypeUsage); 
                    } 
                    RowType edmRowType = new RowType(properties, sspaceRowType.InitializerMetadata);
                    result = TypeUsage.Create(edmRowType, this.Facets); 
                }
                else if (Helper.IsCollectionType(edmType))
                {
                    CollectionType sspaceCollectionType = ((CollectionType)edmType); 
                    TypeUsage newTypeUsage = sspaceCollectionType.TypeUsage.GetModelTypeUsage();
                    result = TypeUsage.Create(new CollectionType(newTypeUsage), this.Facets); 
                } 
                else if (Helper.IsRefType(edmType))
                { 
                    System.Diagnostics.Debug.Assert(((RefType)edmType).ElementType.DataSpace == DataSpace.CSpace);
                    result = this;
                }
                else if (Helper.IsPrimitiveType(edmType)) 
                {
                    result = ((PrimitiveType)edmType).ProviderManifest.GetEdmType(this); 
 
                    if (result == null)
                    { 
                        throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Mapping_ProviderReturnsNullType(this.ToString()));
                    }

                    if (!TypeSemantics.IsNullable(this)) 
                    {
                        result = TypeUsage.Create(result.EdmType, 
                            OverrideFacetValues(result.Facets, 
                                new FacetValues{ Nullable = false }));
                    } 
                }
                else if (Helper.IsEntityTypeBase(edmType) || Helper.IsComplexType(edmType))
                {
                    result = this; 
                }
                else 
                { 
                    System.Diagnostics.Debug.Assert(false, "Unexpected type found in entity data reader");
                    return null; 
                }
                System.Threading.Interlocked.CompareExchange(ref _modelTypeUsage, result, null);
            }
            return _modelTypeUsage; 
        }
 
        ///  
        /// check if "this" is a subtype of the specified TypeUsage
        ///  
        /// The typeUsage to be checked
        /// true if this typeUsage is a subtype of the specified typeUsage
        public bool IsSubtypeOf(TypeUsage typeUsage)
        { 
            if (EdmType == null || typeUsage == null)
            { 
                return false; 
            }
 
            return EdmType.IsSubtypeOf(typeUsage.EdmType);
        }

        private IEnumerable GetFacets() 
        {
            foreach (FacetDescription facetDescription in _edmType.GetAssociatedFacetDescriptions()) 
            { 
                yield return facetDescription.DefaultValueFacet;
            } 
        }

        internal override void SetReadOnly()
        { 
            Debug.Fail("TypeUsage.SetReadOnly should not need to ever be called");
            base.SetReadOnly(); 
        } 

        ///  
        /// returns the identity of the type usage
        /// 
        internal override String Identity
        { 
            get
            { 
                if (this.Facets.Count == 0) 
                {
                    return this.EdmType.Identity; 
                }

                if (this._identity == null)
                { 
                    StringBuilder builder = new StringBuilder(128);
                    BuildIdentity(builder); 
                    string identity = builder.ToString(); 
                    System.Threading.Interlocked.CompareExchange(ref _identity, identity, null);
                } 
                return this._identity;
            }
        }
 
        private static IEnumerable GetDefaultFacetDescriptionsAndOverrideFacetValues(EdmType type, FacetValues values)
        { 
            return OverrideFacetValues(type.GetAssociatedFacetDescriptions(), 
                fd => fd,
                fd => fd.DefaultValueFacet, 
                values);
        }

 
        private static IEnumerable OverrideFacetValues(IEnumerable facets, FacetValues values)
        { 
            return OverrideFacetValues(facets, 
                f => f.Description,
                f => f, 
                values);
        }

 
        private static IEnumerable OverrideFacetValues(IEnumerable facetThings,
                Func getDescription, 
                Func getFacet, 
                FacetValues values)
        { 
            // yield all the non custom values
            foreach (var thing in facetThings)
            {
                FacetDescription description = getDescription(thing); 
                Facet facet;
                if (!description.IsConstant && values.TryGetFacet(description, out facet)) 
                { 
                    yield return facet;
                } 
                else
                {
                    yield return getFacet(thing);
                } 
            }
 
        } 

        internal override void BuildIdentity(StringBuilder builder) 
        {
            // if we've already cached the identity, simply append it
            if (null != _identity)
            { 
                builder.Append(_identity);
                return; 
            } 

            builder.Append(this.EdmType.Identity); 

            builder.Append("(");
            bool first = true;
            for (int j = 0; j < this.Facets.Count; j++) 
            {
                Facet facet = this.Facets[j]; 
 
                if (0 <= Array.BinarySearch(s_identityFacets, facet.Name, StringComparer.Ordinal))
                { 
                    if (first) { first = false; }
                    else { builder.Append(","); }

                    builder.Append(facet.Name); 
                    builder.Append("=");
                    // If the facet is present, add its value to the identity 
                    // We only include built-in system facets for the identity 
                    builder.Append(facet.Value ?? String.Empty);
                } 
            }
            builder.Append(")");
        }
 
        /// 
        ///  
        public override string ToString() 
        {
            return EdmType.ToString(); 
        }

        /// 
        /// EdmEquals override verifying the equivalence of all facets. Two facets are considered 
        /// equal if they have the same name and the same value (Object.Equals)
        ///  
        ///  
        /// 
        internal override bool EdmEquals(MetadataItem item) 
        {
            // short-circuit if this and other are reference equivalent
            if (Object.ReferenceEquals(this, item)) { return true; }
 
            // check type of item
            if (null == item || BuiltInTypeKind.TypeUsage != item.BuiltInTypeKind) { return false; } 
            TypeUsage other = (TypeUsage)item; 

            // verify edm types are equivalent 
            if (!this.EdmType.EdmEquals(other.EdmType)) { return false; }

            // if both usages have default facets, no need to compare
            if (null == this._facets && null == other._facets) { return true; } 

            // initialize facets and compare 
            if (this.Facets.Count != other.Facets.Count) { return false; } 

            foreach (Facet thisFacet in this.Facets) 
            {
                Facet otherFacet;
                if (!other.Facets.TryGetValue(thisFacet.Name, false, out otherFacet))
                { 
                    // other type usage doesn't have the same facets as this type usage
                    return false; 
                } 

                // check that the facet values are the same 
                if (!Object.Equals(thisFacet.Value, otherFacet.Value))
                {
                    return false;
                } 
            }
 
            return true; 
        }
 
        private static void ValidateMaxLength(int maxLength)
        {
            if (maxLength <= 0)
            { 
                throw EntityUtil.ArgumentOutOfRange(System.Data.Entity.Strings.InvalidMaxLengthSize, "maxLength");
            } 
        } 

        #endregion 

    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization; 
using System.Text;
using System.Data.Common.Utils; 
using System.Linq; 

namespace System.Data.Metadata.Edm 
{
    /// 
    /// Class representing a type information for an item
    ///  
    [DebuggerDisplay("EdmType={EdmType}, Facets.Count={Facets.Count}")]
    public sealed class TypeUsage : MetadataItem 
    { 
        #region Constructors
 
        /// 
        /// The constructor for TypeUsage taking in a type
        /// 
        /// The type which the TypeUsage object describes 
        /// Thrown if edmType argument is null
        private TypeUsage(EdmType edmType) 
        :base(MetadataFlags.Readonly) 
        {
            EntityUtil.GenericCheckArgumentNull(edmType, "edmType"); 

            _edmType = edmType;

            // I would like to be able to assert that the edmType is ReadOnly, but 
            // because some types are still in loading while the TypeUsage is being created
            // that won't work. We should consider a way to change this 
        } 

        ///  
        /// The constructor for TypeUsage taking in a type and a collection of facets
        /// 
        /// The type which the TypeUsage object describes
        /// The replacement collection of facets 
        /// Thrown if edmType argument is null
        private TypeUsage(EdmType edmType, IEnumerable facets) 
            : this(edmType) 
        {
            MetadataCollection facetCollection = new MetadataCollection(facets); 
            facetCollection.SetReadOnly();
            _facets = facetCollection.AsReadOnlyMetadataCollection();
        }
        #endregion 

        #region Factory Methods 
        ///  
        /// Factory method for creating a TypeUsage with specified EdmType
        ///  
        /// EdmType for which to create a type usage
        /// new TypeUsage instance with default facet values
        internal static TypeUsage Create(EdmType edmType)
        { 
            return new TypeUsage(edmType);
        } 
 
        /// 
        /// Factory method for creating a TypeUsage with specified EdmType 
        /// 
        /// EdmType for which to create a type usage
        /// new TypeUsage instance with default facet values
        internal static TypeUsage Create(EdmType edmType, FacetValues values) 
        {
            return new TypeUsage(edmType, 
                GetDefaultFacetDescriptionsAndOverrideFacetValues(edmType, values)); 
        }
 
        /// 
        /// Factory method for creating a TypeUsage with specified EdmType and facets
        /// 
        /// EdmType for which to create a type usage 
        /// facets to be copied into the new TypeUsage
        /// new TypeUsage instance 
        internal static TypeUsage Create(EdmType edmType, IEnumerable facets) 
        {
            return new TypeUsage(edmType, facets); 
        }

        internal TypeUsage ShallowCopy(FacetValues facetValues)
        { 
            return TypeUsage.Create(_edmType, OverrideFacetValues(Facets, facetValues));
        } 
 
        /// 
        /// Factory method for creating a "readonly" TypeUsage with specified EdmType 
        /// 
        /// An EdmType for which to create a TypeUsage
        /// A TypeUsage instance with default facet values for the specified EdmType
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "0#edm")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
        public static TypeUsage CreateDefaultTypeUsage(EdmType edmType) 
        { 
            EntityUtil.CheckArgumentNull(edmType, "edmType");
 
            TypeUsage type = TypeUsage.Create(edmType);
            return type;
        }
 
        /// 
        /// Factory method for creating a string TypeUsage object with the specified facets 
        ///  
        /// A PrimitiveType for which to construct the TypeUsage
        /// Whether the string type is unicode or not 
        /// Whether the string type is fixed length or not
        /// The max length of the string type
        /// A TypeUsage object describing a string type with the given facet values
        public static TypeUsage CreateStringTypeUsage(PrimitiveType primitiveType, 
                                                      bool isUnicode,
                                                      bool isFixedLength, 
                                                      int maxLength) 
        {
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.String)
            {
                throw EntityUtil.NotStringTypeForTypeUsage(); 
            }
 
            ValidateMaxLength(maxLength); 

            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ MaxLength = maxLength, Unicode = isUnicode, FixedLength = isFixedLength});

            return typeUsage;
        } 

        ///  
        /// Factory method for creating a string TypeUsage object with the specified facets and 
        /// unbounded MaxLength
        ///  
        /// A PrimitiveType for which to construct the TypeUsage
        /// Whether the string type is unicode or not
        /// Whether the string type is fixed length or not
        /// A TypeUsage object describing a string type with the given facet values 
        /// and unbounded MaxLength
        public static TypeUsage CreateStringTypeUsage(PrimitiveType primitiveType, 
                                                      bool isUnicode, 
                                                      bool isFixedLength)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.String)
            { 
                throw EntityUtil.NotStringTypeForTypeUsage();
            } 
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ MaxLength = TypeUsage.DefaultMaxLengthFacetValue,
                                  Unicode = isUnicode, FixedLength = isFixedLength}); 

            return typeUsage;
        }
 

        ///  
        /// Factory method for creating a Binary TypeUsage object with the specified facets 
        /// 
        /// A PrimitiveType for which to construct TypeUsage 
        /// Whether the binary type is fixed length or not
        /// The max length of the binary type
        /// A TypeUsage object describing a binary type with the given facet values
        public static TypeUsage CreateBinaryTypeUsage(PrimitiveType primitiveType, 
                                                      bool isFixedLength,
                                                      int maxLength) 
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Binary)
            {
                throw EntityUtil.NotBinaryTypeForTypeUsage();
            } 

            ValidateMaxLength(maxLength); 
 
            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{MaxLength = maxLength, FixedLength = isFixedLength}); 

            return typeUsage;
        }
 
        /// 
        /// Factory method for creating a Binary TypeUsage object with the specified facets and 
        /// unbounded MaxLength 
        /// 
        /// A PrimitiveType for which to construct the TypeUsage 
        /// Whether the binary type is fixed length or not
        /// A TypeUsage object describing a binary type with the given facet values
        public static TypeUsage CreateBinaryTypeUsage(PrimitiveType primitiveType, bool isFixedLength)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Binary) 
            {
                throw EntityUtil.NotBinaryTypeForTypeUsage(); 
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{MaxLength = TypeUsage.DefaultMaxLengthFacetValue,
                                 FixedLength = isFixedLength}); 

            return typeUsage; 
        } 

        ///  
        /// Factory method for creating a DateTime TypeUsage object with the specified facets
        /// 
        /// A PrimitiveType for which to construct the TypeUsage
        /// Precision for seconds 
        /// A TypeUsage object describing a DateTime type with the given facet values
        public static TypeUsage CreateDateTimeTypeUsage(PrimitiveType primitiveType, 
                                                        byte? precision) 
        {
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.DateTime)
            {
                throw EntityUtil.NotDateTimeTypeForTypeUsage(); 
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{Precision = precision}); 

            return typeUsage; 
        }

        /// 
        /// Factory method for creating a DateTimeOffset TypeUsage object with the specified facets 
        /// 
        /// A PrimitiveType for which to construct the TypeUsage 
        /// Precision for seconds 
        /// A TypeUsage object describing a DateTime type with the given facet values
        public static TypeUsage CreateDateTimeOffsetTypeUsage(PrimitiveType primitiveType, 
                                                        byte? precision)
        {
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.DateTimeOffset)
            { 
                throw EntityUtil.NotDateTimeOffsetTypeForTypeUsage(); 
            }
 
            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{ Precision = precision });

            return typeUsage; 
        }
 
        ///  
        /// Factory method for creating a Time TypeUsage object with the specified facets
        ///  
        /// A PrimitiveType for which to construct the TypeUsage
        /// Precision for seconds
        /// A TypeUsage object describing a Time type with the given facet values
        public static TypeUsage CreateTimeTypeUsage(PrimitiveType primitiveType, 
                                                        byte? precision)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Time) 
            {
                throw EntityUtil.NotTimeTypeForTypeUsage();
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ Precision = precision });
 
            return typeUsage; 
        }
 


        /// 
        /// Factory method for creating a Decimal TypeUsage object with the specified facets 
        /// 
        /// A PrimitiveType for which to construct type usage 
        /// The precision of the decimal type 
        /// The scale of the decimal type
        /// A TypeUsage object describing a decimal type with the given facet values 
        public static TypeUsage CreateDecimalTypeUsage(PrimitiveType primitiveType,
                                                       byte precision,
                                                       byte scale)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType");
 
            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal) 
            {
                throw EntityUtil.NotDecimalTypeForTypeUsage(); 
            }

            TypeUsage typeUsage = TypeUsage.Create(primitiveType,
                new FacetValues{Precision = precision, Scale = scale }); 

            return typeUsage; 
        } 

        ///  
        /// Factory method for creating a Decimal TypeUsage object with unbounded precision and scale
        /// 
        /// The PrimitiveType for which to construct type usage
        /// A TypeUsage object describing a decimal type with unbounded precision and scale 
        public static TypeUsage CreateDecimalTypeUsage(PrimitiveType primitiveType)
        { 
            EntityUtil.CheckArgumentNull(primitiveType, "primitiveType"); 

            if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal) 
            {
                throw EntityUtil.NotDecimalTypeForTypeUsage();
            }
            TypeUsage typeUsage = TypeUsage.Create(primitiveType, 
                new FacetValues{ Precision = TypeUsage.DefaultPrecisionFacetValue, Scale = TypeUsage.DefaultScaleFacetValue });
 
            return typeUsage; 
        }
        #endregion 

        #region Fields
        private TypeUsage _modelTypeUsage;
        private readonly EdmType _edmType; 
        private ReadOnlyMetadataCollection _facets;
        private string _identity; 
 
        /// 
        /// Set of facets that should be included in identity for TypeUsage 
        /// 
        /// keep this sorted for binary searching
        private static readonly string[] s_identityFacets = new string[] {
            DbProviderManifest.DefaultValueFacetName, 
            DbProviderManifest.FixedLengthFacetName,
            DbProviderManifest.MaxLengthFacetName, 
            DbProviderManifest.NullableFacetName, 
            DbProviderManifest.PrecisionFacetName,
            DbProviderManifest.ScaleFacetName, 
            DbProviderManifest.UnicodeFacetName,
        };

        internal static readonly EdmConstants.Unbounded DefaultMaxLengthFacetValue       = EdmConstants.UnboundedValue; 
        internal static readonly EdmConstants.Unbounded DefaultPrecisionFacetValue       = EdmConstants.UnboundedValue;
        internal static readonly EdmConstants.Unbounded DefaultScaleFacetValue           = EdmConstants.UnboundedValue; 
        internal static readonly bool                   DefaultUnicodeFacetValue         = true; 
        internal static readonly bool                   DefaultFixedLengthFacetValue     = false;
        internal static readonly byte?                   DefaultDateTimePrecisionFacetValue = null; 

        #endregion

        #region Properties 
        /// 
        /// Returns the kind of the type 
        ///  
        public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.TypeUsage; } }
 
        /// 
        /// Gets the type that this TypeUsage describes
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")] 
        [MetadataProperty(BuiltInTypeKind.EdmType, false)]
        public EdmType EdmType 
        { 
            get
            { 
                return _edmType;
            }
        }
 
        /// 
        /// Gets the list of facets for the type in this TypeUsage 
        ///  
        [MetadataProperty(BuiltInTypeKind.Facet, true)]
        public ReadOnlyMetadataCollection Facets 
        {
            get
            {
                if (null == _facets) 
                {
                    MetadataCollection facets = new MetadataCollection(GetFacets()); 
                    // we never modify the collection so we can set it readonly from the start 
                    facets.SetReadOnly();
                    System.Threading.Interlocked.CompareExchange(ref _facets, facets.AsReadOnlyMetadataCollection(), null); 
                }
                return _facets;
            }
        } 
        #endregion
 
        #region Methods 
        /// 
        /// Returns a Model type usage for a provider type 
        /// 
        /// model (CSpace) type usage
        internal TypeUsage GetModelTypeUsage()
        { 
            if (_modelTypeUsage == null)
            { 
                EdmType edmType = this.EdmType; 

                // If the edm type is already a cspace type, return the same type 
                if (edmType.DataSpace == DataSpace.CSpace || edmType.DataSpace == DataSpace.OSpace)
                {
                    return this;
                } 

                TypeUsage result; 
                if (Helper.IsRowType(edmType)) 
                {
                    RowType sspaceRowType = (RowType)edmType; 
                    EdmProperty[] properties = new EdmProperty[sspaceRowType.Properties.Count];
                    for (int i = 0; i < properties.Length; i++)
                    {
                        EdmProperty sspaceProperty = sspaceRowType.Properties[i]; 
                        TypeUsage newTypeUsage = sspaceProperty.TypeUsage.GetModelTypeUsage();
                        properties[i] = new EdmProperty(sspaceProperty.Name, newTypeUsage); 
                    } 
                    RowType edmRowType = new RowType(properties, sspaceRowType.InitializerMetadata);
                    result = TypeUsage.Create(edmRowType, this.Facets); 
                }
                else if (Helper.IsCollectionType(edmType))
                {
                    CollectionType sspaceCollectionType = ((CollectionType)edmType); 
                    TypeUsage newTypeUsage = sspaceCollectionType.TypeUsage.GetModelTypeUsage();
                    result = TypeUsage.Create(new CollectionType(newTypeUsage), this.Facets); 
                } 
                else if (Helper.IsRefType(edmType))
                { 
                    System.Diagnostics.Debug.Assert(((RefType)edmType).ElementType.DataSpace == DataSpace.CSpace);
                    result = this;
                }
                else if (Helper.IsPrimitiveType(edmType)) 
                {
                    result = ((PrimitiveType)edmType).ProviderManifest.GetEdmType(this); 
 
                    if (result == null)
                    { 
                        throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Mapping_ProviderReturnsNullType(this.ToString()));
                    }

                    if (!TypeSemantics.IsNullable(this)) 
                    {
                        result = TypeUsage.Create(result.EdmType, 
                            OverrideFacetValues(result.Facets, 
                                new FacetValues{ Nullable = false }));
                    } 
                }
                else if (Helper.IsEntityTypeBase(edmType) || Helper.IsComplexType(edmType))
                {
                    result = this; 
                }
                else 
                { 
                    System.Diagnostics.Debug.Assert(false, "Unexpected type found in entity data reader");
                    return null; 
                }
                System.Threading.Interlocked.CompareExchange(ref _modelTypeUsage, result, null);
            }
            return _modelTypeUsage; 
        }
 
        ///  
        /// check if "this" is a subtype of the specified TypeUsage
        ///  
        /// The typeUsage to be checked
        /// true if this typeUsage is a subtype of the specified typeUsage
        public bool IsSubtypeOf(TypeUsage typeUsage)
        { 
            if (EdmType == null || typeUsage == null)
            { 
                return false; 
            }
 
            return EdmType.IsSubtypeOf(typeUsage.EdmType);
        }

        private IEnumerable GetFacets() 
        {
            foreach (FacetDescription facetDescription in _edmType.GetAssociatedFacetDescriptions()) 
            { 
                yield return facetDescription.DefaultValueFacet;
            } 
        }

        internal override void SetReadOnly()
        { 
            Debug.Fail("TypeUsage.SetReadOnly should not need to ever be called");
            base.SetReadOnly(); 
        } 

        ///  
        /// returns the identity of the type usage
        /// 
        internal override String Identity
        { 
            get
            { 
                if (this.Facets.Count == 0) 
                {
                    return this.EdmType.Identity; 
                }

                if (this._identity == null)
                { 
                    StringBuilder builder = new StringBuilder(128);
                    BuildIdentity(builder); 
                    string identity = builder.ToString(); 
                    System.Threading.Interlocked.CompareExchange(ref _identity, identity, null);
                } 
                return this._identity;
            }
        }
 
        private static IEnumerable GetDefaultFacetDescriptionsAndOverrideFacetValues(EdmType type, FacetValues values)
        { 
            return OverrideFacetValues(type.GetAssociatedFacetDescriptions(), 
                fd => fd,
                fd => fd.DefaultValueFacet, 
                values);
        }

 
        private static IEnumerable OverrideFacetValues(IEnumerable facets, FacetValues values)
        { 
            return OverrideFacetValues(facets, 
                f => f.Description,
                f => f, 
                values);
        }

 
        private static IEnumerable OverrideFacetValues(IEnumerable facetThings,
                Func getDescription, 
                Func getFacet, 
                FacetValues values)
        { 
            // yield all the non custom values
            foreach (var thing in facetThings)
            {
                FacetDescription description = getDescription(thing); 
                Facet facet;
                if (!description.IsConstant && values.TryGetFacet(description, out facet)) 
                { 
                    yield return facet;
                } 
                else
                {
                    yield return getFacet(thing);
                } 
            }
 
        } 

        internal override void BuildIdentity(StringBuilder builder) 
        {
            // if we've already cached the identity, simply append it
            if (null != _identity)
            { 
                builder.Append(_identity);
                return; 
            } 

            builder.Append(this.EdmType.Identity); 

            builder.Append("(");
            bool first = true;
            for (int j = 0; j < this.Facets.Count; j++) 
            {
                Facet facet = this.Facets[j]; 
 
                if (0 <= Array.BinarySearch(s_identityFacets, facet.Name, StringComparer.Ordinal))
                { 
                    if (first) { first = false; }
                    else { builder.Append(","); }

                    builder.Append(facet.Name); 
                    builder.Append("=");
                    // If the facet is present, add its value to the identity 
                    // We only include built-in system facets for the identity 
                    builder.Append(facet.Value ?? String.Empty);
                } 
            }
            builder.Append(")");
        }
 
        /// 
        ///  
        public override string ToString() 
        {
            return EdmType.ToString(); 
        }

        /// 
        /// EdmEquals override verifying the equivalence of all facets. Two facets are considered 
        /// equal if they have the same name and the same value (Object.Equals)
        ///  
        ///  
        /// 
        internal override bool EdmEquals(MetadataItem item) 
        {
            // short-circuit if this and other are reference equivalent
            if (Object.ReferenceEquals(this, item)) { return true; }
 
            // check type of item
            if (null == item || BuiltInTypeKind.TypeUsage != item.BuiltInTypeKind) { return false; } 
            TypeUsage other = (TypeUsage)item; 

            // verify edm types are equivalent 
            if (!this.EdmType.EdmEquals(other.EdmType)) { return false; }

            // if both usages have default facets, no need to compare
            if (null == this._facets && null == other._facets) { return true; } 

            // initialize facets and compare 
            if (this.Facets.Count != other.Facets.Count) { return false; } 

            foreach (Facet thisFacet in this.Facets) 
            {
                Facet otherFacet;
                if (!other.Facets.TryGetValue(thisFacet.Name, false, out otherFacet))
                { 
                    // other type usage doesn't have the same facets as this type usage
                    return false; 
                } 

                // check that the facet values are the same 
                if (!Object.Equals(thisFacet.Value, otherFacet.Value))
                {
                    return false;
                } 
            }
 
            return true; 
        }
 
        private static void ValidateMaxLength(int maxLength)
        {
            if (maxLength <= 0)
            { 
                throw EntityUtil.ArgumentOutOfRange(System.Data.Entity.Strings.InvalidMaxLengthSize, "maxLength");
            } 
        } 

        #endregion 

    }
}

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