1- // Copyright (C) 2003-2010 Xtensive LLC.
1+ // Copyright (C) 2008-2021 Xtensive LLC.
22// All rights reserved.
33// For conditions of distribution and use, see license.
44// Created by: Alexey Gamzov
99using System . Diagnostics ;
1010using System . Reflection ;
1111using System . Runtime . Serialization ;
12+ using System . Security ;
1213using System . Text ;
1314using System . Threading ;
1415using Xtensive . Collections ;
@@ -25,18 +26,20 @@ namespace Xtensive.Core
2526 /// </summary>
2627 [ Serializable ]
2728 public abstract class AssociateProvider :
28- IDeserializationCallback
29+ IDeserializationCallback ,
30+ ISerializable
2931 {
3032 private static readonly AsyncLocal < SetSlim < TypePair > > inProgressAsync = new AsyncLocal < SetSlim < TypePair > > ( ) ;
3133
3234 private static SetSlim < TypePair > InProgress
3335 {
3436 get {
35- if ( inProgressAsync . Value == null )
37+ if ( inProgressAsync . Value == null ) {
3638 inProgressAsync . Value = new SetSlim < TypePair > ( ) ;
39+ }
3740 return inProgressAsync . Value ;
3841 }
39- set { inProgressAsync . Value = value ; }
42+ set => inProgressAsync . Value = value ;
4043 }
4144
4245 [ NonSerialized ]
@@ -55,19 +58,20 @@ private static SetSlim<TypePair> InProgress
5558 protected object [ ] ConstructorParams
5659 {
5760 [ DebuggerStepThrough ]
58- get { return constructorParams ; }
61+ get => constructorParams ;
5962 [ DebuggerStepThrough ]
60- set { constructorParams = value ; }
63+ set => constructorParams = value ;
6164 }
6265
6366 /// <summary>
6467 /// Gets or sets associate type suffixes.
6568 /// </summary>
66- protected string [ ] TypeSuffixes {
69+ protected string [ ] TypeSuffixes
70+ {
6771 [ DebuggerStepThrough ]
68- get { return typeSuffixes ; }
72+ get => typeSuffixes ;
6973 [ DebuggerStepThrough ]
70- set { typeSuffixes = value ; }
74+ set => typeSuffixes = value ;
7175 }
7276
7377 /// <summary>
@@ -91,10 +95,12 @@ protected void AddHighPriorityLocation(Assembly assembly, string nameSpace, bool
9195 {
9296 lock ( _lock ) {
9397 var newHighPriorityLocations = new List < Pair < Assembly , string > > ( highPriorityLocations ) ;
94- if ( overriding )
98+ if ( overriding ) {
9599 newHighPriorityLocations . Insert ( 0 , new Pair < Assembly , string > ( assembly , nameSpace ) ) ;
96- else
100+ }
101+ else {
97102 newHighPriorityLocations . Add ( new Pair < Assembly , string > ( assembly , nameSpace ) ) ;
103+ }
98104 Thread . MemoryBarrier ( ) ;
99105 highPriorityLocations = newHighPriorityLocations ;
100106 }
@@ -103,10 +109,7 @@ protected void AddHighPriorityLocation(Assembly assembly, string nameSpace, bool
103109 /// <summary>
104110 /// Gets a list of high priority locations.
105111 /// </summary>
106- protected List < Pair < Assembly , string > > HighPriorityLocations
107- {
108- get { return highPriorityLocations ; }
109- }
112+ protected List < Pair < Assembly , string > > HighPriorityLocations => highPriorityLocations ;
110113
111114 /// <summary>
112115 /// Gets associate instance for specified parameter and result types.
@@ -120,11 +123,9 @@ protected List<Pair<Assembly, string>> HighPriorityLocations
120123 protected TResult GetAssociate < TKey , TAssociate , TResult > ( )
121124 where TAssociate : class
122125 {
123- var key = new TypePair ( typeof ( TKey ) , typeof ( TResult ) ) ;
124- return ( TResult ) cache . GetValue ( key , _key => {
125- Type foundFor ;
126- return ConvertAssociate < TKey , TAssociate , TResult > ( CreateAssociate < TKey , TAssociate > ( out foundFor ) ) ;
127- } ) ;
126+ var key = new TypePair ( typeof ( TKey ) , typeof ( TResult ) ) ;
127+ return ( TResult ) cache . GetValue ( key ,
128+ _key => ConvertAssociate < TKey , TAssociate , TResult > ( CreateAssociate < TKey , TAssociate > ( out var foundFor ) ) ) ;
128129 }
129130
130131 /// <summary>
@@ -141,30 +142,22 @@ protected TResult GetAssociate<TKey, TAssociate, TResult>()
141142 protected TResult GetAssociate < TKey1 , TKey2 , TAssociate , TResult > ( )
142143 where TAssociate : class
143144 {
144- var key = new TypePair ( typeof ( TKey1 ) , typeof ( TResult ) ) ;
145+ var key = new TypePair ( typeof ( TKey1 ) , typeof ( TResult ) ) ;
145146 return ( TResult ) cache . GetValue ( key , _key => {
146- Type foundFor ;
147- TAssociate associate1 = CreateAssociate < TKey1 , TAssociate > ( out foundFor ) ;
148- TAssociate associate2 = CreateAssociate < TKey2 , TAssociate > ( out foundFor ) ;
147+ var associate1 = CreateAssociate < TKey1 , TAssociate > ( out var foundFor ) ;
148+ var associate2 = CreateAssociate < TKey2 , TAssociate > ( out foundFor ) ;
149149 // Preferring non-null ;)
150- TAssociate associate ;
151- if ( associate1 == null )
152- associate = associate2 ;
153- else if ( associate2 == null )
154- associate = associate1 ;
155- else
156- // Both are non-null; preferring one of two
157- associate = PreferAssociate < TKey1 , TKey2 , TAssociate > ( associate1 , associate2 ) ;
158- if ( associate == null ) {
150+ var associate = associate1 ?? associate2 ?? PreferAssociate < TKey1 , TKey2 , TAssociate > ( associate1 , associate2 ) ;
151+ if ( associate == null ) {
159152 // Try to get complex associate (create it manually)
160153 associate = CreateCustomAssociate < TKey1 , TKey2 , TAssociate > ( ) ;
161- if ( associate == null ) {
154+ if ( associate == null ) {
162155 var stringBuilder = new StringBuilder ( ) ;
163- for ( int i = 0 ; i < TypeSuffixes . Length ; i ++ ) {
164- if ( i != 0 ) {
165- stringBuilder . Append ( ", " ) ;
156+ for ( var i = 0 ; i < TypeSuffixes . Length ; i ++ ) {
157+ if ( i != 0 ) {
158+ _ = stringBuilder . Append ( ", " ) ;
166159 }
167- stringBuilder . Append ( TypeSuffixes [ i ] ) ;
160+ _ = stringBuilder . Append ( TypeSuffixes [ i ] ) ;
168161 }
169162 throw new InvalidOperationException ( string . Format (
170163 Strings . ExCantFindAssociate2 , stringBuilder ,
@@ -189,12 +182,9 @@ protected TResult GetAssociate<TKey1, TKey2, TAssociate, TResult>()
189182 protected virtual TAssociate PreferAssociate < TKey1 , TKey2 , TAssociate > ( TAssociate associate1 ,
190183 TAssociate associate2 )
191184 {
192- int locationPosition1 = GetAssociateLocationPosition ( associate1 ) ;
193- int locationPosition2 = GetAssociateLocationPosition ( associate2 ) ;
194- if ( locationPosition1 <= locationPosition2 )
195- return associate1 ;
196- else
197- return associate2 ;
185+ var locationPosition1 = GetAssociateLocationPosition ( associate1 ) ;
186+ var locationPosition2 = GetAssociateLocationPosition ( associate2 ) ;
187+ return locationPosition1 <= locationPosition2 ? associate1 : associate2 ;
198188 }
199189
200190 /// <summary>
@@ -211,9 +201,11 @@ protected int GetAssociateLocationPosition<TAssociate>(TAssociate associate)
211201 associate . GetType ( ) . Assembly ,
212202 associate . GetType ( ) . Namespace ) ;
213203 var hpl = HighPriorityLocations ;
214- for ( int i = 0 ; i < hpl . Count ; i ++ )
215- if ( AdvancedComparerStruct < Pair < Assembly , string > > . Default . Equals ( hpl [ i ] , entry ) )
204+ for ( var i = 0 ; i < hpl . Count ; i ++ ) {
205+ if ( AdvancedComparerStruct < Pair < Assembly , string > > . Default . Equals ( hpl [ i ] , entry ) ) {
216206 return i ;
207+ }
208+ }
217209 return int . MaxValue ;
218210 }
219211
@@ -229,19 +221,22 @@ protected int GetAssociateLocationPosition<TAssociate>(TAssociate associate)
229221 protected virtual TAssociate CreateAssociate < TKey , TAssociate > ( out Type foundFor )
230222 where TAssociate : class
231223 {
232- if ( InProgress == null )
224+ if ( InProgress == null ) {
233225 InProgress = new SetSlim < TypePair > ( ) ;
234- var progressionMark = new TypePair ( typeof ( TKey ) , typeof ( TAssociate ) ) ;
235- if ( InProgress . Contains ( progressionMark ) )
226+ }
227+
228+ var progressionMark = new TypePair ( typeof ( TKey ) , typeof ( TAssociate ) ) ;
229+ if ( InProgress . Contains ( progressionMark ) ) {
236230 throw new InvalidOperationException ( Strings . ExRecursiveAssociateLookupDetected ) ;
237- InProgress . Add ( progressionMark ) ;
231+ }
232+ _ = InProgress . Add ( progressionMark ) ;
238233 try {
239234 var associate = TypeHelper . CreateAssociate < TAssociate > (
240- typeof ( TKey ) , out foundFor , TypeSuffixes , constructorParams , highPriorityLocations ) ;
235+ typeof ( TKey ) , out foundFor , TypeSuffixes , constructorParams , highPriorityLocations ) ;
241236 return associate ;
242237 }
243238 finally {
244- InProgress . Remove ( progressionMark ) ;
239+ _ = InProgress . Remove ( progressionMark ) ;
245240 }
246241 }
247242
@@ -255,9 +250,7 @@ protected virtual TAssociate CreateAssociate<TKey, TAssociate>(out Type foundFor
255250 /// <returns>Associate instance or <see langword="null"/>.</returns>
256251 protected virtual TAssociate CreateCustomAssociate < TKey1 , TKey2 , TAssociate > ( )
257252 where TAssociate : class
258- {
259- return null ;
260- }
253+ => null ;
261254
262255 /// <summary>
263256 /// Converts <paramref name="associate"/> to <typeparamref name="TResult"/> object.
@@ -268,9 +261,7 @@ protected virtual TAssociate CreateCustomAssociate<TKey1, TKey2, TAssociate>()
268261 /// <param name="associate">Associate to convert to result.</param>
269262 /// <returns>Conversion result.</returns>
270263 protected virtual TResult ConvertAssociate < TKey , TAssociate , TResult > ( TAssociate associate )
271- {
272- return ( TResult ) ( object ) associate ;
273- }
264+ => ( TResult ) ( object ) associate ;
274265
275266 /// <summary>
276267 /// Converts <paramref name="associate"/> to <typeparamref name="TResult"/> object.
@@ -282,9 +273,7 @@ protected virtual TResult ConvertAssociate<TKey, TAssociate, TResult>(TAssociate
282273 /// <param name="associate">Associate to convert to result.</param>
283274 /// <returns>Conversion result.</returns>
284275 protected virtual TResult ConvertAssociate < TKey1 , TKey2 , TAssociate , TResult > ( TAssociate associate )
285- {
286- return ( TResult ) ( object ) associate ;
287- }
276+ => ( TResult ) ( object ) associate ;
288277
289278
290279 // Constructors
@@ -294,11 +283,28 @@ protected virtual TResult ConvertAssociate<TKey1, TKey2, TAssociate, TResult>(TA
294283 /// </summary>
295284 protected AssociateProvider ( )
296285 {
297- constructorParams = new object [ ] { this } ;
286+ constructorParams = new object [ ] { this } ;
298287 _lock = new object ( ) ;
299288 cache = ThreadSafeDictionary < TypePair , object > . Create ( _lock ) ;
300289 }
301290
291+ protected AssociateProvider ( SerializationInfo info , StreamingContext context )
292+ {
293+ if ( info == null ) {
294+ throw new ArgumentNullException ( nameof ( info ) ) ;
295+ }
296+
297+ var constructorParamsExceptThis = ( object [ ] ) info . GetValue ( nameof ( constructorParams ) , typeof ( object [ ] ) ) ;
298+ constructorParams = new object [ constructorParamsExceptThis . Length + 1 ] ;
299+ constructorParams [ 0 ] = this ;
300+ Array . Copy ( constructorParamsExceptThis , 0 , constructorParams , 1 , constructorParamsExceptThis . Length ) ;
301+
302+ typeSuffixes = ( string [ ] ) info . GetValue ( nameof ( typeSuffixes ) , typeof ( string [ ] ) ) ;
303+
304+ var highPriorityLocationsSerializable = ( List < Pair < string , string > > ) info . GetValue ( nameof ( highPriorityLocations ) , typeof ( List < Pair < string , string > > ) ) ;
305+ highPriorityLocations = highPriorityLocationsSerializable . SelectToList ( ls => new Pair < Assembly , string > ( Assembly . Load ( ls . First ) , ls . Second ) ) ;
306+ }
307+
302308 /// <summary>
303309 /// Performs post-deserialization actions.
304310 /// </summary>
@@ -308,5 +314,25 @@ public virtual void OnDeserialization(object sender)
308314 _lock = new object ( ) ;
309315 cache = ThreadSafeDictionary < TypePair , object > . Create ( _lock ) ;
310316 }
317+
318+ /// <inheritdoc/>
319+ [ SecurityCritical ]
320+ public virtual void GetObjectData ( SerializationInfo info , StreamingContext context )
321+ {
322+ object [ ] constructorParamsExceptThis = null ;
323+ // need to exclude this form parameters to prevent loop
324+ if ( constructorParams . Length == 1 ) {
325+ constructorParamsExceptThis = Array . Empty < object > ( ) ;
326+ }
327+ else {
328+ constructorParamsExceptThis = new object [ constructorParams . Length - 1 ] ;
329+ Array . Copy ( constructorParams , 1 , constructorParamsExceptThis , 0 , constructorParamsExceptThis . Length ) ;
330+ }
331+ info . AddValue ( nameof ( constructorParams ) , constructorParamsExceptThis , constructorParams . GetType ( ) ) ;
332+ info . AddValue ( nameof ( typeSuffixes ) , typeSuffixes , typeSuffixes . GetType ( ) ) ;
333+
334+ var highPriorityLocationsSerializable = highPriorityLocations . SelectToList ( l => new Pair < string , string > ( l . First . FullName , l . Second ) ) ;
335+ info . AddValue ( nameof ( highPriorityLocations ) , highPriorityLocationsSerializable , highPriorityLocationsSerializable . GetType ( ) ) ;
336+ }
311337 }
312338}
0 commit comments