Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / Edm / EdmType.cs
1 //---------------------------------------------------------------------
2 // <copyright file="EdmType.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9 using System.Data.Common;
10 using System.Globalization;
11 using System.Diagnostics;
12 using System.Collections.Generic;
13 using System.Text;
14 using System.Threading;
15
16 namespace System.Data.Metadata.Edm
17 {
18     /// <summary>
19     /// Base EdmType class for all the model types
20     /// </summary>
21     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
22     public abstract class EdmType : GlobalItem
23     {
24         #region Constructors
25         /// <summary>
26         /// Initializes a new instance of EdmType
27         /// </summary>
28         internal EdmType()
29         {
30             // No initialization of item attributes in here, it's used as a pass thru in the case for delay population
31             // of item attributes
32         }
33
34         /// <summary>
35         /// Constructs a new instance of EdmType with the given name, namespace and version
36         /// </summary>
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,
43                          string namespaceName,
44                          DataSpace dataSpace)
45         {
46             EntityUtil.GenericCheckArgumentNull(name, "name");
47             EntityUtil.GenericCheckArgumentNull(namespaceName, "namespaceName");
48
49             // Initialize the item attributes
50             EdmType.Initialize(this,
51                                name,
52                                namespaceName,
53                                dataSpace,
54                                false,
55                                null);
56         }
57         #endregion
58
59         #region Fields
60         private CollectionType _collectionType;
61         private string _identity;
62         private string _name;
63         private string _namespace;
64         private EdmType _baseType;
65         #endregion
66
67         #region Properties
68         /// <summary>
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
72         /// </summary>
73         internal string CacheIdentity
74         {
75             get
76             {
77                 return _identity;
78             }
79             private set
80             {
81                 _identity = value;
82             }
83         }
84
85         /// <summary>
86         /// Returns the identity of the edm type
87         /// </summary>
88         internal override string Identity
89         {
90             get
91             {
92                 if (this.CacheIdentity == null)
93                 {
94                     StringBuilder builder = new StringBuilder(50);
95                     BuildIdentity(builder);
96                     this.CacheIdentity = builder.ToString();
97                 }
98                 return this.CacheIdentity;
99             }
100         }
101
102         /// <summary>
103         /// Returns the name of the EdmType
104         /// </summary>
105         [MetadataProperty(PrimitiveTypeKind.String, false)]
106         public String Name
107         {
108             get
109             {
110                 return _name;
111             }
112             internal set
113             {
114                 Debug.Assert(value != null, "The name should never be set to null");
115                 _name = value; 
116             }
117         }
118
119         /// <summary>
120         /// Returns the namespace of the EdmType
121         /// </summary>
122         [MetadataProperty(PrimitiveTypeKind.String, false)]
123         public String NamespaceName
124         {
125             get
126             {
127                 return _namespace;
128             }
129             internal set
130             {
131                 Debug.Assert(value != null, "Namespace should never be set to null");
132                 _namespace = value;
133             }
134         }
135
136         /// <summary>
137         /// Returns true if the EdmType is abstract
138         /// </summary>
139         /// <exception cref="System.InvalidOperationException">Thrown if the setter is called on instance that is in ReadOnly state</exception>
140         [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
141         public bool Abstract
142         {
143             get
144             {
145                 return GetFlag(MetadataFlags.IsAbstract);
146             }
147             internal set
148             {
149                 SetFlag(MetadataFlags.IsAbstract, value);
150             }
151         }
152
153         /// <summary>
154         /// Returns the base type of the EdmType
155         /// </summary>
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
160         {
161             get
162             {
163                 return _baseType;
164             }
165             internal set
166             {
167                 Util.ThrowIfReadOnly(this);
168                 Debug.Assert(_baseType == null, "BaseType can't be set multiple times");
169
170                 // Check to make sure there won't be a loop in the inheritance
171                 EdmType type = value;
172                 while (type != null)
173                 {
174                     Debug.Assert(type != this, "Cannot set the given type as base type because it would introduce a loop in inheritance");
175
176                     type = type.BaseType;
177                 }
178
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");
185
186                 _baseType = value;
187             }
188         }
189
190         /// <summary>
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
195         /// </summary>
196         public virtual string FullName
197         {
198             get
199             {
200                 return this.Identity;
201            }
202         }
203
204         /// <summary>
205         /// If OSpace, return the CLR Type else null
206         /// </summary>
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
209         {
210             get { return null; }
211         }
212
213         internal override void BuildIdentity(StringBuilder builder)
214         {
215             // if we already know the identity, simply append it
216             if (null != this.CacheIdentity)
217             {
218                 builder.Append(this.CacheIdentity);
219                 return;
220             }
221
222             builder.Append(CreateEdmTypeIdentity(NamespaceName, Name));
223         }
224
225         internal static string CreateEdmTypeIdentity(string namespaceName, string name)
226         {
227             string identity = string.Empty;
228             if (string.Empty != namespaceName)
229             {
230                 identity = namespaceName + ".";
231             }
232
233             identity += name;
234
235             return identity;
236             
237         }
238
239         #endregion
240
241         #region Methods
242         /// <summary>
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
245         /// </summary>
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>
254         internal static void 
255             Initialize(EdmType edmType,
256                                         string name,
257                                         string namespaceName,
258                                         DataSpace dataSpace,
259                                         bool isAbstract,
260                                         EdmType baseType)
261         {
262             edmType._baseType = baseType;
263             edmType._name = name;
264             edmType._namespace = namespaceName;
265             edmType.DataSpace = dataSpace;
266             edmType.Abstract = isAbstract;
267         }
268
269         /// <summary>
270         /// Overriding System.Object.ToString to provide better String representation 
271         /// for this type.
272         /// </summary>
273         public override string ToString()
274         {
275             return this.FullName;
276         }
277
278         /// <summary>
279         /// Returns the collection type whose element type is this edm type
280         /// </summary>
281         public CollectionType GetCollectionType()
282         {
283             if (_collectionType == null)
284             {
285                 Interlocked.CompareExchange<CollectionType>(ref _collectionType, new CollectionType(this), null);
286             }
287
288             return _collectionType;
289         }
290
291         /// <summary>
292         /// check to see if otherType is among the base types,
293         /// </summary>
294         /// <param name="otherType"></param>
295         /// <returns>
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.
299         /// </returns>
300         internal virtual bool IsSubtypeOf(EdmType otherType)
301         {
302             return Helper.IsSubtypeOf(this, otherType);
303         }
304
305         /// <summary>
306         /// check to see if otherType is among the sub-types,
307         /// </summary>
308         /// <param name="otherType"></param>
309         /// <returns>
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.
313         /// </returns>
314         internal virtual bool IsBaseTypeOf(EdmType otherType)
315         {
316             if (otherType == null)
317                 return false;
318             return otherType.IsSubtypeOf(this);
319         }
320
321         /// <summary>
322         /// Check if this type is assignable from otherType
323         /// </summary>
324         /// <param name="otherType"></param>
325         /// <returns></returns>
326         internal virtual bool IsAssignableFrom(EdmType otherType)
327         {
328             return Helper.IsAssignableFrom(this, otherType);
329         }
330
331         /// <summary>
332         /// Sets this item to be readonly, once this is set, the item will never be writable again.
333         /// </summary>
334         internal override void SetReadOnly()
335         {
336             if (!IsReadOnly)
337             {
338                 base.SetReadOnly();
339
340                 EdmType baseType = BaseType;
341                 if (baseType != null)
342                 {
343                     baseType.SetReadOnly();
344                 }
345             }
346         }
347
348         /// <summary>
349         /// Returns all facet descriptions associated with this type.
350         /// </summary>
351         /// <returns>Descriptions for all built-in facets for this type.</returns>
352         internal virtual IEnumerable<FacetDescription> GetAssociatedFacetDescriptions()
353         {
354             return MetadataItem.GetGeneralFacetDescriptions();
355         }
356         #endregion
357     }
358 }