66
77using System ;
88using System . Collections ;
9- using System . Collections . Generic ;
109using System . Collections . Immutable ;
10+ using System . Collections . Generic ;
1111using System . Collections . ObjectModel ;
1212using System . Diagnostics ;
1313using System . Linq ;
1717using Xtensive . Tuples ;
1818using Xtensive . Tuples . Transform ;
1919using Tuple = Xtensive . Tuples . Tuple ;
20+ using JetBrains . Annotations ;
2021
2122namespace Xtensive . Orm . Model
2223{
@@ -39,7 +40,7 @@ public sealed class TypeInfo : SchemaMappedNode
3940 /// </summary>
4041 public const int MinTypeId = 100 ;
4142
42- private static readonly IReadOnlySet < TypeInfo > EmptyTypes = ImmutableHashSet < TypeInfo > . Empty ;
43+ private static readonly ImmutableHashSet < TypeInfo > EmptyTypes = ImmutableHashSet . Create < TypeInfo > ( ) ;
4344
4445 private readonly ColumnInfoCollection columns ;
4546 private readonly FieldMap fieldMap ;
@@ -69,15 +70,45 @@ public sealed class TypeInfo : SchemaMappedNode
6970 private FieldInfo typeIdField ;
7071
7172 private TypeInfo ancestor ;
73+
74+ private IReadOnlySet < TypeInfo > ancestors ;
75+
76+ private ISet < TypeInfo > directDescendants ;
77+ private IReadOnlySet < TypeInfo > allDescendants ;
78+ private ISet < TypeInfo > directInterfaces ;
79+ private IReadOnlySet < TypeInfo > allInterfaces ;
80+ private ISet < TypeInfo > directImplementors ;
81+ private IReadOnlySet < TypeInfo > allImplementors ;
82+ private IReadOnlySet < TypeInfo > typeWithAncestorsAndInterfaces ;
83+
84+ #region Hierarchical structure properties
85+
86+ /// <summary>
87+ /// Gets the ancestor.
88+ /// </summary>
7289 public TypeInfo Ancestor {
73- get => ancestor ;
74- internal set => ancestor = ancestor == null ? value : throw Exceptions . AlreadyInitialized ( nameof ( Ancestor ) ) ;
90+ get { return ancestor ; }
91+ internal set {
92+ if ( ancestor != null )
93+ throw Exceptions . AlreadyInitialized ( nameof ( Ancestor ) ) ;
94+ ancestor = value ;
95+ }
7596 }
7697
98+ /// <summary>
99+ /// Gets the root of the hierarchy.
100+ /// </summary>
101+ [ CanBeNull ]
102+ public TypeInfo Root =>
103+ IsInterface || IsStructure
104+ ? null
105+ : IsLocked
106+ ? Hierarchy . Root
107+ : Ancestors . FirstOrDefault ( ) ?? this ;
108+
77109 /// <summary>
78110 /// Gets the ancestors recursively. Inheritor-to-root order.
79111 /// </summary>
80- /// <returns>The ancestor</returns>
81112 public IEnumerable < TypeInfo > AncestorChain
82113 {
83114 get {
@@ -87,93 +118,103 @@ public IEnumerable<TypeInfo> AncestorChain
87118 }
88119 }
89120
90- private IReadOnlyList < TypeInfo > ancestors ;
91-
92121 /// <summary>
93- /// Gets the ancestors recursively. Root-to-inheritor order. Reverse of AncestorChain.
122+ /// Gets the ancestors recursively. Root-to-inheritor order. Reverse of <see cref=" AncestorChain"/> .
94123 /// </summary>
95- /// <returns>The ancestor</returns >
96- public IReadOnlyList < TypeInfo > Ancestors => ancestors ??= AncestorChain . Reverse ( ) . ToList ( ) ;
124+ public IReadOnlySet < TypeInfo > Ancestors = >
125+ ancestors ??= new Collections . ReadOnlyHashSet < TypeInfo > ( AncestorChain . Reverse ( ) . ToHashSet ( ) ) ;
97126
98- private HashSet < TypeInfo > descendants ;
99- public IReadOnlySet < TypeInfo > DirectDescendants => descendants ?? EmptyTypes ;
127+ /// <summary>
128+ /// Gets direct descendants of this instance.
129+ /// </summary>
130+ public IReadOnlySet < TypeInfo > DirectDescendants =>
131+ ( IReadOnlySet < TypeInfo > ) directDescendants ?? EmptyTypes ;
100132
101- private IReadOnlySet < TypeInfo > recursiveDescendants ;
133+ /// <summary>
134+ /// Gets all descendants (both direct and nested) of this instance.
135+ /// </summary>
102136 public IReadOnlySet < TypeInfo > AllDescendants
103137 {
104138 get {
105- if ( recursiveDescendants == null ) {
139+ if ( allDescendants == null ) {
106140 if ( DirectDescendants . Count == 0 ) {
107- recursiveDescendants = DirectDescendants ;
141+ allDescendants = DirectDescendants ;
108142 }
109143 else {
110144 var set = new HashSet < TypeInfo > ( DirectDescendants ) ;
111145 set . UnionWith ( DirectDescendants . SelectMany ( static o => o . AllDescendants ) ) ;
112- recursiveDescendants = set ;
146+ allDescendants = new Collections . ReadOnlyHashSet < TypeInfo > ( set ) ;
113147 }
114148 }
115- return recursiveDescendants ;
149+ return allDescendants ;
116150 }
117151 }
118152
119- private HashSet < TypeInfo > interfaces ;
120- public IReadOnlySet < TypeInfo > DirectInterfaces => interfaces ?? EmptyTypes ;
121-
122- private IReadOnlyList < TypeInfo > recursiveInterfaces ;
123- public IReadOnlyList < TypeInfo > AllInterfaces =>
124- recursiveInterfaces ??= ( IsInterface ? DirectInterfaces : DirectInterfaces . Concat ( AncestorChain . SelectMany ( static o => o . DirectInterfaces ) ) ) . ToList ( ) ;
153+ /// <summary>
154+ /// Gets the persistent interfaces this instance implements directly.
155+ /// </summary>
156+ public IReadOnlySet < TypeInfo > DirectInterfaces =>
157+ ( IReadOnlySet < TypeInfo > ) directInterfaces ?? EmptyTypes ;
125158
126- private HashSet < TypeInfo > implementors ;
159+ /// <summary>
160+ /// Gets all the persistent interfaces (both direct and non-direct) this instance implements.
161+ /// </summary>
162+ public IReadOnlySet < TypeInfo > AllInterfaces =>
163+ allInterfaces ??= ( IsInterface
164+ ? DirectInterfaces
165+ : new Collections . ReadOnlyHashSet < TypeInfo > ( DirectInterfaces . Concat ( AncestorChain . SelectMany ( static o => o . DirectInterfaces ) ) . ToHashSet ( ) ) ) ;
127166
128167 /// <summary>
129168 /// Gets the direct implementors of this instance.
130169 /// </summary>
131- public IReadOnlySet < TypeInfo > DirectImplementors => implementors ?? EmptyTypes ;
170+ public IReadOnlySet < TypeInfo > DirectImplementors =>
171+ ( IReadOnlySet < TypeInfo > ) directImplementors ?? EmptyTypes ;
132172
133- private IReadOnlyList < TypeInfo > recursiveImplementors ;
134- public IReadOnlyList < TypeInfo > AllImplementors
173+
174+ /// <summary>
175+ /// Gets both direct and non-direct implementors of this instance.
176+ /// </summary>
177+ public IReadOnlySet < TypeInfo > AllImplementors
135178 {
136179 get {
137- if ( recursiveImplementors == null ) {
180+ if ( allImplementors == null ) {
138181 if ( DirectImplementors . Count == 0 ) {
139- recursiveImplementors = Array . Empty < TypeInfo > ( ) ;
182+ allImplementors = EmptyTypes ;
140183 }
141184 else {
142- var list = new List < TypeInfo > ( DirectImplementors . Count ) ;
185+ var allSet = new HashSet < TypeInfo > ( DirectImplementors . Count ) ;
143186 foreach ( var item in DirectImplementors ) {
144- list . Add ( item ) ;
187+ _ = allSet . Add ( item ) ;
145188 if ( ! item . IsInterface ) {
146- list . AddRange ( item . AllDescendants ) ;
189+ foreach ( var descendant in item . AllDescendants )
190+ _ = allSet . Add ( descendant ) ;
147191 }
148192 }
149- recursiveImplementors = list ;
193+ allImplementors = new Collections . ReadOnlyHashSet < TypeInfo > ( allSet ) ;
150194 }
151195 }
152- return recursiveImplementors ;
196+ return allImplementors ;
153197 }
154198 }
155199
156200 /// <summary>
157- /// Gets the ancestors recursively. Root-to-inheritor order .
201+ /// Gets all ancestors, all interfaces with this instacne included .
158202 /// </summary>
159- /// <returns>The ancestor</returns>
160- [ Obsolete ( "Use Ancestors property instead" ) ]
161- public IReadOnlyList < TypeInfo > GetAncestors ( ) => Ancestors ;
162-
163- private IReadOnlySet < TypeInfo > typeWithAncestorsAndInterfaces ;
164- public IReadOnlySet < TypeInfo > TypeWithAncestorsAndInterfaces
203+ internal IReadOnlySet < TypeInfo > TypeWithAncestorsAndInterfaces
165204 {
166205 get {
167206 if ( typeWithAncestorsAndInterfaces == null ) {
168207 var candidates = new HashSet < TypeInfo > ( Ancestors ) ;
169208 candidates . UnionWith ( AllInterfaces ) ;
170- candidates . Add ( this ) ;
209+ _ = candidates . Add ( this ) ;
171210 typeWithAncestorsAndInterfaces = candidates ;
172211 }
173212 return typeWithAncestorsAndInterfaces ;
174213 }
175214 }
176215
216+ #endregion
217+
177218 #region IsXxx properties
178219
179220 /// <summary>
@@ -232,7 +273,7 @@ public bool IsSystem
232273
233274 /// <summary>
234275 /// Gets a value indicating whether this instance is a leaf type,
235- /// i.e. its <see cref="GetDescendants() "/> method returns <see langword="0" /> .
276+ /// i.e. its <see cref="DirectDescendants "/> method returns empty collection .
236277 /// </summary>
237278 public bool IsLeaf
238279 {
@@ -503,28 +544,6 @@ internal set {
503544
504545 internal FieldAccessorProvider Accessors { get ; private set ; }
505546
506- /// <summary>
507- /// Gets the direct implementors of this instance.
508- /// </summary>
509- /// <param name="recursive">if set to <see langword="true"/> then both direct and non-direct implementors will be returned.</param>
510- [ Obsolete ( "Use Implementors/RecursiveImplementors properties instead" ) ]
511- public IEnumerable < TypeInfo > GetImplementors ( bool recursive = false ) => recursive ? AllImplementors : DirectImplementors ;
512-
513- /// <summary>
514- /// Gets the persistent interfaces this instance implements.
515- /// </summary>
516- /// <param name="recursive">if set to <see langword="true"/> then both direct and non-direct implemented interfaces will be returned.</param>
517- [ Obsolete ( "Use Interfaces/RecursiveInterfaces properties instead" ) ]
518- public IEnumerable < TypeInfo > GetInterfaces ( bool recursive = false ) => recursive ? AllInterfaces : DirectInterfaces ;
519-
520- /// <summary>
521- /// Gets descendants of this instance.
522- /// </summary>
523- /// <param name="recursive">if set to <see langword="true"/> then both direct and nested descendants will be returned.</param>
524- /// <returns></returns>
525- [ Obsolete ( "Use Descendants/RecursiveDescendants properties instead" ) ]
526- public IEnumerable < TypeInfo > GetDescendants ( bool recursive ) => recursive ? AllDescendants : DirectDescendants ;
527-
528547 /// <summary>
529548 /// Creates the tuple prototype with specified <paramref name="primaryKey"/>.
530549 /// </summary>
@@ -555,13 +574,42 @@ public Tuple InjectPrimaryKey(Tuple entityTuple, Tuple primaryKey)
555574 return primaryKeyInjector . Apply ( TupleTransformType . Tuple , primaryKey , entityTuple ) ;
556575 }
557576
577+ /// <summary>
578+ /// Gets the direct implementors of this instance.
579+ /// </summary>
580+ /// <param name="recursive">if set to <see langword="true"/> then both direct and non-direct implementors will be returned.</param>
581+ [ Obsolete ( "Use DirectImplementors/AllImplementors properties instead" ) ]
582+ public IEnumerable < TypeInfo > GetImplementors ( bool recursive = false ) => recursive ? AllImplementors : DirectImplementors ;
558583
584+ /// <summary>
585+ /// Gets the persistent interfaces this instance implements.
586+ /// </summary>
587+ /// <param name="recursive">if set to <see langword="true"/> then both direct and non-direct implemented interfaces will be returned.</param>
588+ [ Obsolete ( "Use DirectInterfaces/AllInterfaces properties instead" ) ]
589+ public IEnumerable < TypeInfo > GetInterfaces ( bool recursive = false ) => recursive ? AllInterfaces : DirectInterfaces ;
590+
591+ /// <summary>
592+ /// Gets descendants of this instance.
593+ /// </summary>
594+ /// <param name="recursive">if set to <see langword="true"/> then both direct and nested descendants will be returned.</param>
595+ /// <returns></returns>
596+ [ Obsolete ( "Use DirectDescendants/AllDescendants properties instead" ) ]
597+ public IEnumerable < TypeInfo > GetDescendants ( bool recursive ) => recursive ? AllDescendants : DirectDescendants ;
598+
599+ /// <summary>
600+ /// Gets the ancestors recursively. Root-to-inheritor order.
601+ /// </summary>
602+ /// <returns>The ancestor</returns>
603+ [ Obsolete ( "Use Ancestors property instead" ) ]
604+ public IReadOnlyList < TypeInfo > GetAncestors ( ) => Ancestors . ToList ( ) ;
605+
606+ /// <summary>
607+ /// Gets the root of the hierarchy.
559608 /// </summary>
560609 /// <returns>The hierarchy root.</returns>
561- public TypeInfo GetRoot ( ) =>
562- IsInterface || IsStructure
563- ? null
564- : ( Ancestors . FirstOrDefault ( ) ?? this ) ;
610+ [ Obsolete ( "Use Root property instead" ) ]
611+ [ CanBeNull ]
612+ public TypeInfo GetRoot ( ) => Root ;
565613
566614 public IEnumerable < AssociationInfo > GetTargetAssociations ( )
567615 {
@@ -789,6 +837,16 @@ public override void Lock(bool recursive)
789837
790838 validators = Array . AsReadOnly ( validators . ToArray ( ) ) ;
791839
840+ directDescendants = directDescendants != null
841+ ? new Collections . ReadOnlyHashSet < TypeInfo > ( ( HashSet < TypeInfo > ) directDescendants )
842+ : EmptyTypes ;
843+ directInterfaces = directInterfaces != null
844+ ? new Collections . ReadOnlyHashSet < TypeInfo > ( ( HashSet < TypeInfo > ) directInterfaces )
845+ : EmptyTypes ;
846+ directImplementors = directImplementors != null
847+ ? new Collections . ReadOnlyHashSet < TypeInfo > ( ( HashSet < TypeInfo > ) directImplementors )
848+ : EmptyTypes ;
849+
792850 affectedIndexes . Lock ( true ) ;
793851 indexes . Lock ( true ) ;
794852 columns . Lock ( true ) ;
@@ -798,6 +856,16 @@ public override void Lock(bool recursive)
798856
799857 #region Private / internal methods
800858
859+
860+ internal void AddDescendant ( TypeInfo descendant ) =>
861+ ( directDescendants ??= new HashSet < TypeInfo > ( ) ) . Add ( descendant ) ;
862+
863+ internal void AddInterface ( TypeInfo iface ) =>
864+ ( directInterfaces ??= new HashSet < TypeInfo > ( ) ) . Add ( iface ) ;
865+
866+ internal void AddImplementor ( TypeInfo implementor ) =>
867+ ( directImplementors ??= new HashSet < TypeInfo > ( ) ) . Add ( implementor ) ;
868+
801869 private KeyInfo GetKey ( ) =>
802870 Hierarchy != null ? Hierarchy . Key
803871 : IsInterface ? DirectImplementors . First ( ) . Hierarchy . Key
@@ -902,15 +970,6 @@ public override string ToString()
902970 return Name ;
903971 }
904972
905- internal void AddDescendant ( TypeInfo descendant ) =>
906- ( descendants ??= new ( ) ) . Add ( descendant ) ;
907-
908- internal void AddInterface ( TypeInfo iface ) =>
909- ( interfaces ??= new ( ) ) . Add ( iface ) ;
910-
911- internal void AddImplementor ( TypeInfo implementor ) =>
912- ( implementors ??= new ( ) ) . Add ( implementor ) ;
913-
914973 // Constructors
915974
916975 /// <summary>
0 commit comments