1 //---------------------------------------------------------------------
2 // <copyright file="EdmType.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9 using System.Data.Common;
10 using System.Globalization;
11 using System.Diagnostics;
12 using System.Collections.Generic;
14 using System.Threading;
16 namespace System.Data.Metadata.Edm
19 /// Base EdmType class for all the model types
21 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
22 public abstract class EdmType : GlobalItem
26 /// Initializes a new instance of EdmType
30 // No initialization of item attributes in here, it's used as a pass thru in the case for delay population
35 /// Constructs a new instance of EdmType with the given name, namespace and version
37 /// <param name="name">name of the type</param>
38 /// <param name="namespaceName">namespace of the type</param>
39 /// <param name="version">version of the type</param>
40 /// <param name="dataSpace">dataSpace in which this edmtype belongs to</param>
41 /// <exception cref="System.ArgumentNullException">Thrown if either the name, namespace or version arguments are null</exception>
42 internal EdmType(string name,
46 EntityUtil.GenericCheckArgumentNull(name, "name");
47 EntityUtil.GenericCheckArgumentNull(namespaceName, "namespaceName");
49 // Initialize the item attributes
50 EdmType.Initialize(this,
60 private CollectionType _collectionType;
61 private string _identity;
63 private string _namespace;
64 private EdmType _baseType;
69 /// Direct accessor for the field Identity. The reason we need to do this is that for derived class,
70 /// they want to cache things only when they are readonly. Plus they want to check for null before
71 /// updating the value
73 internal string CacheIdentity
86 /// Returns the identity of the edm type
88 internal override string Identity
92 if (this.CacheIdentity == null)
94 StringBuilder builder = new StringBuilder(50);
95 BuildIdentity(builder);
96 this.CacheIdentity = builder.ToString();
98 return this.CacheIdentity;
103 /// Returns the name of the EdmType
105 [MetadataProperty(PrimitiveTypeKind.String, false)]
114 Debug.Assert(value != null, "The name should never be set to null");
120 /// Returns the namespace of the EdmType
122 [MetadataProperty(PrimitiveTypeKind.String, false)]
123 public String NamespaceName
131 Debug.Assert(value != null, "Namespace should never be set to null");
137 /// Returns true if the EdmType is abstract
139 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called on instance that is in ReadOnly state</exception>
140 [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
145 return GetFlag(MetadataFlags.IsAbstract);
149 SetFlag(MetadataFlags.IsAbstract, value);
154 /// Returns the base type of the EdmType
156 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called on instance that is in ReadOnly state</exception>
157 /// <exception cref="System.ArgumentException">Thrown if the value passed in for setter will create a loop in the inheritance chain</exception>
158 [MetadataProperty(BuiltInTypeKind.EdmType, false)]
159 public EdmType BaseType
167 Util.ThrowIfReadOnly(this);
168 Debug.Assert(_baseType == null, "BaseType can't be set multiple times");
170 // Check to make sure there won't be a loop in the inheritance
171 EdmType type = value;
174 Debug.Assert(type != this, "Cannot set the given type as base type because it would introduce a loop in inheritance");
176 type = type.BaseType;
179 // Also if the base type is EntityTypeBase, make sure it doesn't have keys
180 Debug.Assert(value == null ||
181 !Helper.IsEntityTypeBase(this) ||
182 ((EntityTypeBase)this).KeyMembers.Count == 0 ||
183 ((EntityTypeBase)value).KeyMembers.Count == 0,
184 " For EntityTypeBase, both base type and derived types cannot have keys defined");
191 /// Returns the full name of this type, which is namespace + "." + name.
192 /// Since the identity of all EdmTypes, except EdmFunction, is same as of that
193 /// of the full name, FullName just returns the identity. This property is
194 /// over-ridden in EdmFunctin, just to return NamespaceName + "." + Name
196 public virtual string FullName
200 return this.Identity;
205 /// If OSpace, return the CLR Type else null
207 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called on instance that is in ReadOnly state</exception>
208 internal virtual System.Type ClrType
213 internal override void BuildIdentity(StringBuilder builder)
215 // if we already know the identity, simply append it
216 if (null != this.CacheIdentity)
218 builder.Append(this.CacheIdentity);
222 builder.Append(CreateEdmTypeIdentity(NamespaceName, Name));
225 internal static string CreateEdmTypeIdentity(string namespaceName, string name)
227 string identity = string.Empty;
228 if (string.Empty != namespaceName)
230 identity = namespaceName + ".";
243 /// Initialize the type. This method must be called since for bootstraping we only call the constructor.
244 /// This method will help us initialize the type
246 /// <param name="edmType">The edm type to initialize with item attributes</param>
247 /// <param name="name">The name of this type</param>
248 /// <param name="namespaceName">The namespace of this type</param>
249 /// <param name="version">The version of this type</param>
250 /// <param name="dataSpace">dataSpace in which this edmtype belongs to</param>
251 /// <param name="isAbstract">If the type is abstract</param>
252 /// <param name="isSealed">If the type is sealed</param>
253 /// <param name="baseType">The base type for this type</param>
255 Initialize(EdmType edmType,
257 string namespaceName,
262 edmType._baseType = baseType;
263 edmType._name = name;
264 edmType._namespace = namespaceName;
265 edmType.DataSpace = dataSpace;
266 edmType.Abstract = isAbstract;
270 /// Overriding System.Object.ToString to provide better String representation
273 public override string ToString()
275 return this.FullName;
279 /// Returns the collection type whose element type is this edm type
281 public CollectionType GetCollectionType()
283 if (_collectionType == null)
285 Interlocked.CompareExchange<CollectionType>(ref _collectionType, new CollectionType(this), null);
288 return _collectionType;
292 /// check to see if otherType is among the base types,
294 /// <param name="otherType"></param>
296 /// if otherType is among the base types, return true,
297 /// otherwise returns false.
298 /// when othertype is same as the current type, return false.
300 internal virtual bool IsSubtypeOf(EdmType otherType)
302 return Helper.IsSubtypeOf(this, otherType);
306 /// check to see if otherType is among the sub-types,
308 /// <param name="otherType"></param>
310 /// if otherType is among the sub-types, returns true,
311 /// otherwise returns false.
312 /// when othertype is same as the current type, return false.
314 internal virtual bool IsBaseTypeOf(EdmType otherType)
316 if (otherType == null)
318 return otherType.IsSubtypeOf(this);
322 /// Check if this type is assignable from otherType
324 /// <param name="otherType"></param>
325 /// <returns></returns>
326 internal virtual bool IsAssignableFrom(EdmType otherType)
328 return Helper.IsAssignableFrom(this, otherType);
332 /// Sets this item to be readonly, once this is set, the item will never be writable again.
334 internal override void SetReadOnly()
340 EdmType baseType = BaseType;
341 if (baseType != null)
343 baseType.SetReadOnly();
349 /// Returns all facet descriptions associated with this type.
351 /// <returns>Descriptions for all built-in facets for this type.</returns>
352 internal virtual IEnumerable<FacetDescription> GetAssociatedFacetDescriptions()
354 return MetadataItem.GetGeneralFacetDescriptions();