diff --git a/Orm/Xtensive.Orm/Caching/WeakCache.cs b/Orm/Xtensive.Orm/Caching/WeakCache.cs index 0d025a62ef..cbd19b04d3 100644 --- a/Orm/Xtensive.Orm/Caching/WeakCache.cs +++ b/Orm/Xtensive.Orm/Caching/WeakCache.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2003-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Alex Ustinov // Created: 2007.05.28 @@ -8,6 +8,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; using System.Security; using Xtensive.Core; @@ -34,7 +35,6 @@ public class WeakCache : /// protected const int NoGcCount = 1024; - private const int GcOperationCost = 2; private readonly bool trackResurrection; private readonly Converter keyExtractor; private Dictionary items; @@ -43,48 +43,44 @@ public class WeakCache : #region Properites: KeyExtractor, ChainedCache, TrackResurrection, EfficiencyFactor, Count, Size /// - public Converter KeyExtractor { + public Converter KeyExtractor + { [DebuggerStepThrough] - get { return keyExtractor; } + get => keyExtractor; } /// /// Gets a value indicating whether this cache tracks resurrection. /// - public bool TrackResurrection { + public bool TrackResurrection + { [DebuggerStepThrough] - get { return trackResurrection; } + get => trackResurrection; } /// - public int Count { + public int Count + { [DebuggerStepThrough] - get { return items.Count; } + get => items?.Count ?? 0; } #endregion /// - public TItem this[TKey key, bool markAsHit] { - get { - TItem item; - if (TryGetItem(key, markAsHit, out item)) - return item; - else - return null; - } - } + public TItem this[TKey key, bool markAsHit] => TryGetItem(key, markAsHit, out var item) ? item : null; /// [SecuritySafeCritical] public virtual bool TryGetItem(TKey key, bool markAsHit, out TItem item) { RegisterOperation(1); - GCHandle cached; - if (items.TryGetValue(key, out cached)) { - item = (TItem) cached.Target; - if (item!=null) + if (items != null && items.TryGetValue(key, out var cached)) { + item = ExtractTarget(cached); + if (item != null) { return true; + } + items.Remove(key); cached.Free(); return false; @@ -94,52 +90,46 @@ public virtual bool TryGetItem(TKey key, bool markAsHit, out TItem item) } /// - public bool Contains(TItem item) - { - return ContainsKey(KeyExtractor(item)); - } + public bool Contains(TItem item) => ContainsKey(KeyExtractor(item)); /// - public bool ContainsKey(TKey key) - { - TItem item; - return TryGetItem(key, false, out item); - } + public bool ContainsKey(TKey key) => TryGetItem(key, false, out var _); #region Modification methods: Add, Remove, Clear /// - public void Add(TItem item) - { - Add(item, true); - } + public void Add(TItem item) => Add(item, true); /// [SecuritySafeCritical] public virtual TItem Add(TItem item, bool replaceIfExists) { - ArgumentValidator.EnsureArgumentNotNull(item, "item"); + ArgumentValidator.EnsureArgumentNotNull(item, nameof(item)); RegisterOperation(2); var key = KeyExtractor(item); - GCHandle cached; - if (items.TryGetValue(key, out cached)) { - if (!replaceIfExists) { - var cachedItem = (TItem) cached.Target; - if (cachedItem!=null) - return cachedItem; + if (items == null) { + items = CreateDictionary(); + } + else if (replaceIfExists) { + if (items.Remove(key, out var cached)) { + cached.Free(); + } + } + else if (items.TryGetValue(key, out var cached)) { + if (ExtractTarget(cached) is TItem cachedItem) { + return cachedItem; } items.Remove(key); cached.Free(); } - items[key] = GCHandle.Alloc(item, - trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak); + items[key] = GCHandle.Alloc(item, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak); return item; } /// public void Remove(TItem item) { - ArgumentValidator.EnsureArgumentNotNull(item, "item"); + ArgumentValidator.EnsureArgumentNotNull(item, nameof(item)); RemoveKey(KeyExtractor(item)); } @@ -147,60 +137,56 @@ public void Remove(TItem item) [SecuritySafeCritical] public virtual void RemoveKey(TKey key) { - GCHandle cached; - if (items.TryGetValue(key, out cached)) { - items.Remove(key); + if (items != null && items.Remove(key, out var cached) == true) { cached.Free(); } } /// - public void RemoveKey(TKey key, bool removeCompletely) - { - RemoveKey(key); - } + public void RemoveKey(TKey key, bool removeCompletely) => RemoveKey(key); /// [SecuritySafeCritical] public virtual void Clear() { + if (items == null) { + return; + } try { - foreach (var pair in items) + foreach (var pair in items) { try { pair.Value.Free(); } - catch {} + catch { } + } } finally { - items = new Dictionary(); + items = null; time = 0; } } /// - public void Invalidate() - { - Clear(); - } + public void Invalidate() => Clear(); /// [SecuritySafeCritical] public virtual void CollectGarbage() { - int count = items.Count; - if (count<=NoGcCount) + var count = items?.Count ?? 0; + if (count <= NoGcCount) { return; + } Exception error = null; int removedCount = 0; try { // Filtering - var newItems = new Dictionary(); - foreach (var pair in items) { - var cached = pair.Value; + var newItems = CreateDictionary(); + foreach (var (key, cached) in items) { var item = cached.Target; - if (item!=null) - newItems.Add(pair.Key, cached); + if (item != null) + newItems.Add(key, cached); else cached.Free(); } @@ -217,7 +203,7 @@ public virtual void CollectGarbage() // Logging if (CoreLog.IsLogged(LogLevel.Debug)) { CoreLog.Debug("WeakCache.CollectGarbage: removed: {0} from {1}", removedCount, count); - if (error!=null) + if (error != null) CoreLog.Debug(error, "Caught at WeakCache.CollectGarbage"); } } @@ -229,39 +215,33 @@ public virtual void CollectGarbage() /// [DebuggerStepThrough] - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// public virtual IEnumerator GetEnumerator() { - foreach (var pair in items) { - var item = ExtractTarget(pair.Value); - if (item!=null) + foreach (var pair in items ?? Enumerable.Empty>()) { + if (ExtractTarget(pair.Value) is TItem item) yield return item; } } [SecuritySafeCritical] - private static TItem ExtractTarget(GCHandle handle) - { - return (TItem) handle.Target; - } + private static TItem ExtractTarget(GCHandle handle) => (TItem) handle.Target; #endregion #region Private / internal methods + private static Dictionary CreateDictionary() => new Dictionary(); + private void RegisterOperation(int weight) { time += weight; - var count = items.Count; - if (count <= NoGcCount) - return; - if (time > ((count << 1) + count)) + var count = items?.Count ?? 0; + if (count > NoGcCount && time > (count << 1) + count) { CollectGarbage(); + } } #endregion @@ -279,7 +259,6 @@ public WeakCache(bool trackResurrection, Converter keyExtractor) ArgumentValidator.EnsureArgumentNotNull(keyExtractor, "keyExtractor"); this.trackResurrection = trackResurrection; this.keyExtractor = keyExtractor; - items = new Dictionary(1024); } // Dispose pattern @@ -290,14 +269,7 @@ public WeakCache(bool trackResurrection, Converter keyExtractor) [SecuritySafeCritical] protected virtual void Dispose(bool disposing) { - if (items!=null) { - try { - Clear(); - } - finally { - items = null; - } - } + Clear(); } /// diff --git a/Orm/Xtensive.Orm/Collections/TypeRegistry.cs b/Orm/Xtensive.Orm/Collections/TypeRegistry.cs index 6cf874f2e3..23b6715834 100644 --- a/Orm/Xtensive.Orm/Collections/TypeRegistry.cs +++ b/Orm/Xtensive.Orm/Collections/TypeRegistry.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2003-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Dmitri Maximov // Created: 2007.08.03 @@ -11,7 +11,7 @@ using System.Reflection; using System.Linq; using Xtensive.Core; - +using Xtensive.IoC; namespace Xtensive.Collections { @@ -33,11 +33,12 @@ public class TypeRegistry : LockableBase, private readonly ITypeRegistrationProcessor processor; private bool isProcessingPendingActions = false; private readonly Set assemblies = new Set(); + protected ServiceRegistration[] serviceRegistrations; /// /// Gets assemblies containing registered types. /// - public Set Assemblies{ get { return assemblies; } } + public Set Assemblies { get { return assemblies; } } /// /// Determines whether the specified is contained in this instance. @@ -63,6 +64,7 @@ public void Register(Type type) else { if (typeSet.Contains(type)) return; + serviceRegistrations = null; types.Add(type); typeSet.Add(type); assemblies.Add(type.Assembly); @@ -74,7 +76,7 @@ public void Register(Type type) /// Search is restricted by assembly only. /// /// Assembly to search for types. - /// When + /// When /// method call has thrown an exception or if no suitable types were found. /// When is null. public void Register(Assembly assembly) @@ -90,9 +92,9 @@ public void Register(Assembly assembly) /// /// Assembly to search for types. /// Namespace to search for types. - /// When + /// When /// method call has thrown an exception or if no suitable types were found. - /// When is null + /// When is null /// or is empty string. public void Register(Assembly assembly, string @namespace) { @@ -132,7 +134,7 @@ private void ProcessPendingActions() actions.Clear(); foreach (var action in oldActions) processor.Process(this, action); - if (actions.Count==0) + if (actions.Count == 0) break; } } @@ -182,7 +184,8 @@ IEnumerator IEnumerable.GetEnumerator() /// /// Gets the number of types registered in this instance. /// - public int Count { + public int Count + { get { ProcessPendingActions(); return types.Count; diff --git a/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs b/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs index 4c081cb8c4..3a447cfd87 100644 --- a/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs +++ b/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2003-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Alex Ustinov // Created: 2007.06.01 @@ -17,7 +17,7 @@ namespace Xtensive.Core /// The of second value. [Serializable] [DebuggerDisplay("{First}, {Second}")] - public readonly struct Pair : + public readonly struct Pair : IComparable>, IEquatable> { @@ -44,7 +44,7 @@ public bool Equals(Pair other) public int CompareTo(Pair other) { int result = AdvancedComparerStruct.System.Compare(First, other.First); - if (result!=0) + if (result != 0) return result; return AdvancedComparerStruct.System.Compare(Second, other.Second); } @@ -56,7 +56,7 @@ public int CompareTo(Pair other) /// public override bool Equals(object obj) { - if (obj.GetType()!=typeof (Pair)) + if (obj.GetType() != typeof(Pair)) return false; return Equals((Pair) obj); } diff --git a/Orm/Xtensive.Orm/Core/Pair{T}.cs b/Orm/Xtensive.Orm/Core/Pair{T}.cs index 032710e547..b4c56744b3 100644 --- a/Orm/Xtensive.Orm/Core/Pair{T}.cs +++ b/Orm/Xtensive.Orm/Core/Pair{T}.cs @@ -18,7 +18,7 @@ namespace Xtensive.Core /// The type of both stored values. [Serializable] [DebuggerDisplay("{First}, {Second}")] - public struct Pair : + public readonly struct Pair : IEquatable>, IComparable> { diff --git a/Orm/Xtensive.Orm/IoC/Internals/DefaultServiceContainer.cs b/Orm/Xtensive.Orm/IoC/Internals/DefaultServiceContainer.cs index 16fd7351ff..4a21e9a061 100644 --- a/Orm/Xtensive.Orm/IoC/Internals/DefaultServiceContainer.cs +++ b/Orm/Xtensive.Orm/IoC/Internals/DefaultServiceContainer.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2010-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Alex Yakunin // Created: 2010.01.30 @@ -17,7 +17,7 @@ namespace Xtensive.IoC { internal sealed class DefaultServiceContainer : ServiceContainerBase { - ThreadSafeDictionary containers = + ThreadSafeDictionary containers = ThreadSafeDictionary.Create(new object()); protected override IEnumerable HandleGetAll(Type serviceType) @@ -38,10 +38,7 @@ private IServiceContainer GetContainer(Type serviceType) return containers.GetValue(assembly, _assembly => { var typeRegistry = new TypeRegistry(new ServiceTypeRegistrationProcessor()); typeRegistry.Register(_assembly); - return new ServiceContainer( - from type in typeRegistry - from serviceRegistration in ServiceRegistration.CreateAll(type, true) - select serviceRegistration); + return new ServiceContainer(typeRegistry.SelectMany(type => ServiceRegistration.CreateAll(type, true))); }); } } diff --git a/Orm/Xtensive.Orm/IoC/ServiceContainer.cs b/Orm/Xtensive.Orm/IoC/ServiceContainer.cs index 0216ece297..f990ebbf58 100644 --- a/Orm/Xtensive.Orm/IoC/ServiceContainer.cs +++ b/Orm/Xtensive.Orm/IoC/ServiceContainer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Dmitri Maximov @@ -15,21 +15,25 @@ using Xtensive.IoC.Configuration; using AttributeSearchOptions = Xtensive.Reflection.AttributeSearchOptions; using AppConfiguration = System.Configuration.Configuration; -using ConfigurationSection=Xtensive.IoC.Configuration.ConfigurationSection; +using ConfigurationSection = Xtensive.IoC.Configuration.ConfigurationSection; namespace Xtensive.IoC { + using Key = ValueTuple; + /// /// Default IoC (inversion of control) container implementation. /// [Serializable] public class ServiceContainer : ServiceContainerBase { - private readonly Dictionary> types = - new Dictionary>(); - private readonly Dictionary instances = + private static readonly Type typeofIServiceContainer = typeof(IServiceContainer); + + private readonly Dictionary> types = + new Dictionary>(); + private readonly Dictionary instances = new Dictionary(); - private readonly Dictionary> constructorCache = + private readonly Dictionary> constructorCache = new Dictionary>(); private readonly HashSet creating = new HashSet(); private readonly object _lock = new object(); @@ -42,14 +46,13 @@ protected override object HandleGet(Type serviceType, string name) { // Not very optimal, but... lock (_lock) { - List list; - if (!types.TryGetValue(GetKey(serviceType, name), out list)) - return null; - if (list.Count==0) + if (!types.TryGetValue(GetKey(serviceType, name), out var list)) return null; - if (list.Count > 1) - throw new AmbiguousMatchException(Strings.ExMultipleServicesMatchToTheSpecifiedArguments); - return GetOrCreateInstances(list).Single(); + return list.Count switch { + 0 => null, + 1 => GetOrCreateInstances(list).Single(), + _ => throw new AmbiguousMatchException(Strings.ExMultipleServicesMatchToTheSpecifiedArguments) + }; } } @@ -58,10 +61,9 @@ protected override IEnumerable HandleGetAll(Type serviceType) { // Not very optimal, but... lock (_lock) { - List list; - if (!types.TryGetValue(GetKey(serviceType, null), out list)) - return EnumerableUtils.Empty; - return GetOrCreateInstances(list); + return types.TryGetValue(GetKey(serviceType, null), out var list) + ? GetOrCreateInstances(list) + : Array.Empty(); } } @@ -75,25 +77,25 @@ protected virtual object CreateInstance(ServiceRegistration serviceInfo) { if (creating.Contains(serviceInfo.Type)) throw new ActivationException(Strings.ExRecursiveConstructorParemeterDependencyIsDetected); - Pair cachedInfo; + Pair cachedInfo; var mappedType = serviceInfo.MappedType; if (!constructorCache.TryGetValue(serviceInfo, out cachedInfo)) { var @ctor = ( from c in mappedType.GetConstructors() - where c.GetAttribute(AttributeSearchOptions.InheritNone)!=null + where c.GetAttribute(AttributeSearchOptions.InheritNone) != null select c ).SingleOrDefault(); - if (@ctor==null) + if (@ctor == null) @ctor = mappedType.GetConstructor(ArrayUtils.EmptyArray); - var @params = @ctor==null ? null : @ctor.GetParameters(); + var @params = @ctor == null ? null : @ctor.GetParameters(); cachedInfo = new Pair(@ctor, @params); constructorCache[serviceInfo] = cachedInfo; } var cInfo = cachedInfo.First; - if (cInfo==null) + if (cInfo == null) return null; var pInfos = cachedInfo.Second; - if (pInfos.Length==0) + if (pInfos.Length == 0) return Activator.CreateInstance(mappedType); var args = new object[pInfos.Length]; creating.Add(serviceInfo.Type); @@ -111,13 +113,8 @@ select c #region Private \ internal methods - private static object GetKey(Type serviceType, string name) - { - if (name.IsNullOrEmpty()) - return serviceType; - else - return new ObjectPair(serviceType, name); - } + private static Key GetKey(Type serviceType, string name) => + new Key(serviceType, string.IsNullOrEmpty(name) ? null : name); private IEnumerable GetOrCreateInstances(IEnumerable services) { @@ -128,7 +125,7 @@ private IEnumerable GetOrCreateInstances(IEnumerable GetOrCreateInstances(IEnumerable list; var key = GetKey(serviceRegistration.Type, serviceRegistration.Name); - if (!types.TryGetValue(key, out list)) { - list = new List(); - types[key] = list; + if (!types.TryGetValue(key, out var list)) { + types[key] = list = new List(); } list.Add(serviceRegistration); } @@ -201,25 +196,23 @@ public static IServiceContainer Create(Type containerType, object configuration) public static IServiceContainer Create(Type containerType, object configuration, IServiceContainer parent) { ArgumentValidator.EnsureArgumentNotNull(containerType, "containerType"); - if (!typeof(IServiceContainer).IsAssignableFrom(containerType)) + if (!typeofIServiceContainer.IsAssignableFrom(containerType)) throw new ArgumentException(string.Format( - Strings.ExContainerTypeMustImplementX, typeof(IServiceContainer).GetShortName()), "containerType"); - - var possibleArgs = - Enumerable.Empty() - .Append(new[] {configuration, parent}) - .Append(new[] {configuration}) - .Append(new[] {parent}); - foreach (var args in possibleArgs) { - var ctor = containerType.GetConstructor(args); - if (ctor!=null) - return (IServiceContainer) ctor.Invoke(args); - } - - throw new ArgumentException( - Strings.ExContainerTypeDoesNotProvideASuitableConstructor, "containerType"); + Strings.ExContainerTypeMustImplementX, typeofIServiceContainer.GetShortName()), "containerType"); + + Type configurationType = configuration?.GetType(), + parentType = parent?.GetType(); + return (IServiceContainer)( + FindConstructor(containerType, configurationType, parentType)?.Invoke(new[] { configuration, parent }) + ?? FindConstructor(containerType, configurationType)?.Invoke(new[] { configuration }) + ?? FindConstructor(containerType, parentType)?.Invoke(new[] { parent }) + ?? throw new ArgumentException(Strings.ExContainerTypeDoesNotProvideASuitableConstructor, "containerType") + ); } + private static ConstructorInfo FindConstructor(Type containerType, params Type[] argumentTypes) => + containerType.GetSingleConstructor(argumentTypes); + #endregion /// @@ -270,7 +263,7 @@ public static IServiceContainer Create(ConfigurationSection section, string name return Create(section, name, null); } - /// + /// /// Creates by its configuration. /// /// IoC configuration section. @@ -284,10 +277,8 @@ public static IServiceContainer Create(ConfigurationSection section, string name if (name.IsNullOrEmpty()) name = string.Empty; - ContainerElement configuration = section==null ? null : section.Containers[name]; - - if (configuration==null) - configuration = new ContainerElement(); + ContainerElement configuration = section?.Containers[name] + ?? new ContainerElement(); var registrations = new List(); var typeRegistry = new TypeRegistry(new ServiceTypeRegistrationProcessor()); @@ -299,12 +290,12 @@ public static IServiceContainer Create(ConfigurationSection section, string name foreach (var serviceRegistrationElement in configuration.Explicit) registrations.Add(serviceRegistrationElement.ToNative()); - var currentParent = configuration.Parent.IsNullOrEmpty() - ? parent + var currentParent = configuration.Parent.IsNullOrEmpty() + ? parent : Create(section, configuration.Parent, parent); - - var containerType = configuration.Type.IsNullOrEmpty() ? - typeof(ServiceContainer) : + + var containerType = configuration.Type.IsNullOrEmpty() ? + typeof(ServiceContainer) : Type.GetType(configuration.Type); return Create(containerType, registrations, currentParent); } @@ -337,7 +328,7 @@ public ServiceContainer(IEnumerable configuration) public ServiceContainer(IEnumerable configuration, IServiceContainer parent) : base(parent) { - if (configuration==null) + if (configuration == null) return; foreach (var serviceRegistration in configuration) Register(serviceRegistration); @@ -351,7 +342,7 @@ public override void Dispose() foreach (var pair in instances) { var service = pair.Value; var disposable = service as IDisposable; - if (disposable!=null) + if (disposable != null) toDispose.Add(disposable); } } diff --git a/Orm/Xtensive.Orm/IoC/ServiceRegistration.cs b/Orm/Xtensive.Orm/IoC/ServiceRegistration.cs index 4f50d61254..45d0a3c7fb 100644 --- a/Orm/Xtensive.Orm/IoC/ServiceRegistration.cs +++ b/Orm/Xtensive.Orm/IoC/ServiceRegistration.cs @@ -1,15 +1,15 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2003-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Dmitri Maximov // Created: 2009.10.12 using System; -using Xtensive.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; using Xtensive.Core; -using System.Linq; - using Xtensive.Reflection; +using ServiceRegistrationKey = System.ValueTuple; namespace Xtensive.IoC { @@ -19,6 +19,9 @@ namespace Xtensive.IoC [Serializable] public sealed class ServiceRegistration { + private static readonly ConcurrentDictionary serviceRegistrationsByType = + new ConcurrentDictionary(); + /// /// Gets the type of the service. /// @@ -56,10 +59,8 @@ public sealed class ServiceRegistration /// /// An array of objects. /// - public static ServiceRegistration[] CreateAll(Type type) - { - return CreateAll(type, false); - } + public static ServiceRegistration[] CreateAll(Type type) => + CreateAll(type, false); /// /// Creates an array of objects @@ -67,32 +68,29 @@ public static ServiceRegistration[] CreateAll(Type type) /// by scanning it s. /// /// The type to provide objects for. - /// Return just registrations for which + /// Return just registrations for which /// ==. /// /// An array of objects. /// - public static ServiceRegistration[] CreateAll(Type type, bool defaultOnly) - { + public static ServiceRegistration[] CreateAll(Type type, bool defaultOnly) => + serviceRegistrationsByType.GetOrAdd(new ServiceRegistrationKey(type, defaultOnly), ServiceRegistrationsExtractor); + + private static readonly Func ServiceRegistrationsExtractor = ((Type type, bool defaultOnly) t) => { + (var type, var defaultOnly) = t; ArgumentValidator.EnsureArgumentNotNull(type, "type"); if (type.IsAbstract) - return ArrayUtils.EmptyArray; + return Array.Empty(); var attributes = type.GetAttributes(AttributeSearchOptions.InheritNone); - if (attributes==null) - return ArrayUtils.EmptyArray; - if (defaultOnly) - attributes = attributes.Where(a => a.Default).ToArray(); - if (attributes.Length==0) - return ArrayUtils.EmptyArray; - - var result = new ServiceRegistration[attributes.Length]; - for (int i = 0; i < attributes.Length; i++) { - var sa = attributes[i]; - result[i] = new ServiceRegistration(sa.Type, sa.Name.IsNullOrEmpty() ? null : sa.Name, type, sa.Singleton); + var registrations = new List(attributes.Length); + foreach (var sa in attributes) { + if (!defaultOnly || sa.Default) { + registrations.Add(new ServiceRegistration(sa.Type, sa.Name.IsNullOrEmpty() ? null : sa.Name, type, sa.Singleton)); + } } - return result; - } + return registrations.ToArray(); + }; // Constructors @@ -103,7 +101,7 @@ public static ServiceRegistration[] CreateAll(Type type, bool defaultOnly) /// The type of the service. /// The instance it is mapped to. public ServiceRegistration(Type type, object mappedInstance) - : this (type, null, mappedInstance) + : this(type, null, mappedInstance) { } @@ -129,7 +127,7 @@ public ServiceRegistration(Type type, string name, object mappedInstance) /// The type it is mapped to. /// A value indicating whether this service is singleton. public ServiceRegistration(Type type, Type mappedType, bool singleton) - : this (type, null, mappedType, singleton) + : this(type, null, mappedType, singleton) { } @@ -148,4 +146,4 @@ public ServiceRegistration(Type type, string name, Type mappedType, bool singlet Singleton = singleton; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs index 38daf86a8a..247fb20b55 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using Xtensive.Collections; using System.Linq; +using Xtensive.IoC; using Xtensive.Orm.Internals; using Xtensive.Orm.Upgrade; @@ -42,6 +43,9 @@ public class DomainTypeRegistry : TypeRegistry /// public IEnumerable SessionServices => this.Where(IsSessionService); + public ServiceRegistration[] ServiceRegistrations => + serviceRegistrations ??= SessionServices.SelectMany(ServiceRegistration.CreateAll).ToArray(); + /// /// Gets all the registered implementations. /// diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/GraphContainer.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/GraphContainer.cs index fb95b1e81d..e2400a5639 100644 --- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/GraphContainer.cs +++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/GraphContainer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexander Nikolaev @@ -25,27 +25,28 @@ internal sealed class GraphContainer public RootEntityContainer RootEntityContainer { get; private set; } - public bool ContainsTask { + public bool ContainsTask + { get { - return RootEntityContainer!=null - || (referencedEntityContainers!=null && referencedEntityContainers.Count > 0) - || (entitySetTasks!=null && entitySetTasks.Count > 0); + return RootEntityContainer != null + || (referencedEntityContainers != null && referencedEntityContainers.Count > 0) + || (entitySetTasks != null && entitySetTasks.Count > 0); } } public IEnumerable ReferencedEntityContainers { - get { return referencedEntityContainers!=null ? referencedEntityContainers.Values : null; } + get { return referencedEntityContainers != null ? referencedEntityContainers.Values : null; } } public IEnumerable EntitySetTasks { - get { return entitySetTasks!=null ? entitySetTasks.Values : null; } + get { return entitySetTasks != null ? entitySetTasks.Values : null; } } public void AddEntityColumns(IEnumerable columns) { - if (RootEntityContainer==null) + if (RootEntityContainer == null) RootEntityContainer = new RootEntityContainer(Key, Type, exactType, Manager); RootEntityContainer.AddColumns(columns); } @@ -56,7 +57,7 @@ public void CreateRootEntityContainer( RootEntityContainer = new RootEntityContainer(Key, Type, exactType, Manager); RootEntityContainer.SetColumnCollections(forcedColumns, forcedColumnsToBeLoaded); } - + public void RegisterReferencedEntityContainer( EntityState ownerState, PrefetchFieldDescriptor referencingFieldDescriptor) { @@ -71,28 +72,28 @@ public void RegisterReferencedEntityContainer( public void RegisterEntitySetTask(EntityState ownerState, PrefetchFieldDescriptor referencingFieldDescriptor) { - if (entitySetTasks==null) + if (entitySetTasks == null) entitySetTasks = new Dictionary(); - if (RootEntityContainer==null) + if (RootEntityContainer == null) AddEntityColumns(Key.TypeReference.Type.Fields .Where(field => field.IsPrimaryKey || field.IsSystem).SelectMany(field => field.Columns)); EntitySetTask task; if (!entitySetTasks.TryGetValue(referencingFieldDescriptor.Field, out task)) entitySetTasks.Add(referencingFieldDescriptor.Field, - new EntitySetTask(Key, referencingFieldDescriptor, ownerState!=null, Manager)); - else if (task.ItemCountLimit==null) + new EntitySetTask(Key, referencingFieldDescriptor, ownerState != null, Manager)); + else if (task.ItemCountLimit == null) return; - else if (referencingFieldDescriptor.EntitySetItemCountLimit==null + else if (referencingFieldDescriptor.EntitySetItemCountLimit == null || task.ItemCountLimit < referencingFieldDescriptor.EntitySetItemCountLimit) entitySetTasks[referencingFieldDescriptor.Field] = - new EntitySetTask(Key, referencingFieldDescriptor, ownerState!=null, Manager); + new EntitySetTask(Key, referencingFieldDescriptor, ownerState != null, Manager); } public void NotifyAboutExtractionOfKeysWithUnknownType() { - if (RootEntityContainer!=null) + if (RootEntityContainer != null) RootEntityContainer.NotifyOwnerAboutKeyWithUnknownType(); - if (referencedEntityContainers==null) + if (referencedEntityContainers == null) return; foreach (var pair in referencedEntityContainers) pair.Value.NotifyOwnerAboutKeyWithUnknownType(); @@ -116,14 +117,14 @@ public override bool Equals(object obj) if (ReferenceEquals(this, obj)) return true; var otherType = obj.GetType(); - if (otherType != (typeof (GraphContainer))) + if (otherType != (typeof(GraphContainer))) return false; return Equals((GraphContainer) obj); } public override int GetHashCode() { - if (cachedHashCode==null) + if (cachedHashCode == null) unchecked { cachedHashCode = (Key.GetHashCode() * 397) ^ Type.GetHashCode(); } @@ -134,12 +135,13 @@ public override int GetHashCode() private static bool AreAllForeignKeyColumnsLoaded(EntityState state, FieldInfo field) { - if (state==null || !state.IsTupleLoaded) + if (state == null || !state.IsTupleLoaded) return false; var tuple = state.Tuple; var fieldStateMap = tuple.GetFieldStateMap(TupleFieldState.Available); - for (var i = 0; i < field.MappingInfo.Length; i++) - if (!fieldStateMap[field.MappingInfo.Offset + i]) + var fieldMappingInfo = field.MappingInfo; + for (var i = 0; i < fieldMappingInfo.Length; i++) + if (!fieldStateMap[fieldMappingInfo.Offset + i]) return false; return true; } @@ -163,7 +165,7 @@ private void RegisterFetchByKnownForeignKey(PrefetchFieldDescriptor referencingF TypeInfo exactReferencedType; var hasExactTypeBeenGotten = PrefetchHelper.TryGetExactKeyType(referencedKey, Manager, out exactReferencedType); - if (hasExactTypeBeenGotten!=null) { + if (hasExactTypeBeenGotten != null) { if (hasExactTypeBeenGotten.Value) { targetType = exactReferencedType; areToNotifyOwner = false; @@ -181,7 +183,7 @@ private void RegisterFetchByKnownForeignKey(PrefetchFieldDescriptor referencingF private void RegisterFetchByUnknownForeignKey(PrefetchFieldDescriptor referencingFieldDescriptor) { - if (referencedEntityContainers==null) + if (referencedEntityContainers == null) referencedEntityContainers = new Dictionary(); referencedEntityContainers.Add(referencingFieldDescriptor.Field, new ReferencedEntityContainer(Key, referencingFieldDescriptor, exactType, Manager)); diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/PrefetchHelper.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/PrefetchHelper.cs index 5d9439009d..b7803bb587 100644 --- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/PrefetchHelper.cs +++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/PrefetchHelper.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2009-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Alexander Nikolaev // Created: 2009.10.22 @@ -22,7 +22,7 @@ public static bool IsFieldToBeLoadedByDefault(FieldInfo field) public static ReadOnlyList CreateDescriptorsForFieldsLoadedByDefault(TypeInfo type) { return new ReadOnlyList(type.Fields - .Where(field => field.Parent==null && IsFieldToBeLoadedByDefault(field)) + .Where(field => field.Parent == null && IsFieldToBeLoadedByDefault(field)) .Select(field => new PrefetchFieldDescriptor(field, false, false)).ToList()); } @@ -61,7 +61,6 @@ public static bool AddColumns(IEnumerable candidateColumns, SortedDictionary columns, TypeInfo type) { var result = false; - var primaryIndex = type.Indexes.PrimaryIndex; foreach (var column in candidateColumns) { result = true; if (type.IsInterface == column.Field.DeclaringType.IsInterface) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/EntityFieldExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/EntityFieldExpression.cs index e8bca2d819..c356d3ce5c 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/EntityFieldExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/EntityFieldExpression.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexis Kochetov @@ -165,11 +165,11 @@ public static EntityFieldExpression CreateEntityField(FieldInfo entityField, int var entityType = entityField.ValueType; var persistentType = entityField.ReflectedType.Model.Types[entityType]; - ref var mappingInfo = ref entityField.mappingInfo; + var mappingInfo = entityField.MappingInfo; var mapping = new Segment(mappingInfo.Offset + offset, mappingInfo.Length); var keyFields = persistentType.Key.Fields; var keyExpression = KeyExpression.Create(persistentType, offset + mappingInfo.Offset); - var fields = new List(keyFields.Count + 1) {keyExpression}; + var fields = new List(keyFields.Count + 1) { keyExpression }; foreach (var field in keyFields) { // Do not convert to LINQ. We want to avoid a closure creation here. fields.Add(BuildNestedFieldExpression(field, offset + mappingInfo.Offset)); diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/FieldExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/FieldExpression.cs index 1a17b60b3a..089406138e 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/FieldExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/FieldExpression.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexis Kochetov @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Linq.Expressions; using Xtensive.Core; -using FieldInfo=Xtensive.Orm.Model.FieldInfo; +using FieldInfo = Xtensive.Orm.Model.FieldInfo; namespace Xtensive.Orm.Linq.Expressions { @@ -126,7 +126,7 @@ public static FieldExpression CreateField(FieldInfo field, int offset) throw new ArgumentException(string.Format(Strings.ExFieldXIsNotPrimitive, field.Name), nameof(field)); } - ref var mappingInfo = ref field.mappingInfo; + var mappingInfo = field.MappingInfo; var mapping = new Segment(mappingInfo.Offset + offset, mappingInfo.Length); return new FieldExpression(ExtendedExpressionType.Field, field, mapping, null, false); } @@ -134,10 +134,10 @@ public static FieldExpression CreateField(FieldInfo field, int offset) // Constructors protected FieldExpression( - ExtendedExpressionType expressionType, - FieldInfo field, + ExtendedExpressionType expressionType, + FieldInfo field, in Segment mapping, - ParameterExpression parameterExpression, + ParameterExpression parameterExpression, bool defaultIfEmpty) : base(expressionType, field.Name, field.ValueType, mapping, field.UnderlyingProperty, parameterExpression, defaultIfEmpty) { diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/StructureFieldExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/StructureFieldExpression.cs index aebf33885c..610021b572 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/StructureFieldExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/StructureFieldExpression.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexis Kochetov @@ -176,12 +176,13 @@ public static StructureFieldExpression CreateStructure(FieldInfo structureField, } var persistentType = structureField.ReflectedType.Model.Types[structureField.ValueType]; - var mapping = new Segment(offset + structureField.MappingInfo.Offset, structureField.MappingInfo.Length); + var fieldMappingInfo = structureField.MappingInfo; + var mapping = new Segment(offset + fieldMappingInfo.Offset, fieldMappingInfo.Length); var result = new StructureFieldExpression(persistentType, structureField, mapping, null, false); var processedFields = new List(persistentType.Fields.Count); foreach (var field in persistentType.Fields) { // Do not convert to LINQ. We want to avoid a closure creation here. - processedFields.Add(BuildNestedFieldExpression(field, offset + structureField.MappingInfo.Offset)); + processedFields.Add(BuildNestedFieldExpression(field, offset + fieldMappingInfo.Offset)); } result.Fields = processedFields; diff --git a/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs b/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs index e95608d913..f2dadf0cba 100644 --- a/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs +++ b/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2020 Xtensive LLC. +// Copyright (C) 2007-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Dmitri Maximov @@ -61,7 +61,7 @@ public sealed class FieldInfo : MappedNode, private int? cachedHashCode; private IList validators; - internal Segment mappingInfo; + private Segment mappingInfo; #region IsXxx properties @@ -74,9 +74,8 @@ public int FieldId { [DebuggerStepThrough] get { return fieldId; } - set - { - if (fieldId!=NoFieldId) + set { + if (fieldId != NoFieldId) throw Exceptions.AlreadyInitialized("FieldId"); fieldId = value; } @@ -88,10 +87,9 @@ public int FieldId public bool IsSystem { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.System)!=0; } + get { return (Attributes & FieldAttributes.System) != 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? (Attributes | FieldAttributes.System) @@ -105,10 +103,9 @@ public bool IsSystem public bool SkipVersion { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.SkipVersion)!=0; } + get { return (Attributes & FieldAttributes.SkipVersion) != 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? (Attributes | FieldAttributes.SkipVersion) @@ -122,7 +119,7 @@ public bool SkipVersion public bool ManualVersion { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.ManualVersion)!=0; } + get { return (Attributes & FieldAttributes.ManualVersion) != 0; } } /// @@ -131,7 +128,7 @@ public bool ManualVersion public bool AutoVersion { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.AutoVersion)!=0; } + get { return (Attributes & FieldAttributes.AutoVersion) != 0; } } /// @@ -140,7 +137,7 @@ public bool AutoVersion public bool IsTypeId { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.TypeId)!=0; } + get { return (Attributes & FieldAttributes.TypeId) != 0; } } /// @@ -149,7 +146,7 @@ public bool IsTypeId public bool IsTypeDiscriminator { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.TypeDiscriminator)!=0; } + get { return (Attributes & FieldAttributes.TypeDiscriminator) != 0; } set { Attributes = value ? Attributes | FieldAttributes.TypeDiscriminator : Attributes & ~FieldAttributes.TypeDiscriminator; } } @@ -161,8 +158,7 @@ public bool IsDeclared [DebuggerStepThrough] get { return (Attributes & FieldAttributes.Declared) > 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? (Attributes | FieldAttributes.Declared) & ~FieldAttributes.Inherited @@ -177,8 +173,7 @@ public bool IsEnum { [DebuggerStepThrough] get { return (Attributes & FieldAttributes.Enum) > 0; } - private set - { + private set { this.EnsureNotLocked(); Attributes = value ? (Attributes | FieldAttributes.Enum) @@ -194,8 +189,7 @@ public bool IsInherited [DebuggerStepThrough] get { return (Attributes & FieldAttributes.Inherited) > 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? (Attributes | FieldAttributes.Inherited) & ~FieldAttributes.Declared @@ -209,13 +203,12 @@ public bool IsInherited public bool IsPrimaryKey { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.PrimaryKey)!=0; } + get { return (Attributes & FieldAttributes.PrimaryKey) != 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? Attributes | FieldAttributes.PrimaryKey : Attributes & ~FieldAttributes.PrimaryKey; - if (column!=null) + if (column != null) column.IsPrimaryKey = true; else foreach (FieldInfo childField in Fields) @@ -229,7 +222,7 @@ public bool IsPrimaryKey public bool IsNested { [DebuggerStepThrough] - get { return Parent!=null; } + get { return Parent != null; } } /// @@ -238,10 +231,9 @@ public bool IsNested public bool IsExplicit { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.Explicit)!=0; } + get { return (Attributes & FieldAttributes.Explicit) != 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? Attributes | FieldAttributes.Explicit : Attributes & ~FieldAttributes.Explicit; } @@ -253,10 +245,9 @@ public bool IsExplicit public bool IsInterfaceImplementation { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.InterfaceImplementation)!=0; } + get { return (Attributes & FieldAttributes.InterfaceImplementation) != 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? Attributes | FieldAttributes.InterfaceImplementation : Attributes & ~FieldAttributes.InterfaceImplementation; } @@ -277,7 +268,7 @@ public bool IsPrimitive public bool IsEntity { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.Entity)!=0; } + get { return (Attributes & FieldAttributes.Entity) != 0; } } /// @@ -286,7 +277,7 @@ public bool IsEntity public bool IsStructure { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.Structure)!=0; } + get { return (Attributes & FieldAttributes.Structure) != 0; } } /// @@ -295,7 +286,7 @@ public bool IsStructure public bool IsEntitySet { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.EntitySet)!=0; } + get { return (Attributes & FieldAttributes.EntitySet) != 0; } } /// @@ -304,10 +295,9 @@ public bool IsEntitySet public bool IsNullable { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.Nullable)!=0; } + get { return (Attributes & FieldAttributes.Nullable) != 0; } [DebuggerStepThrough] - private set - { + private set { this.EnsureNotLocked(); Attributes = value ? Attributes | FieldAttributes.Nullable : Attributes & ~FieldAttributes.Nullable; } @@ -319,10 +309,9 @@ private set public bool IsLazyLoad { [DebuggerStepThrough] - get { return (Attributes & FieldAttributes.LazyLoad)!=0; } + get { return (Attributes & FieldAttributes.LazyLoad) != 0; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); Attributes = value ? Attributes | FieldAttributes.LazyLoad : Attributes & ~FieldAttributes.LazyLoad; } @@ -336,8 +325,7 @@ public bool IsLazyLoad public string OriginalName { get { return originalName; } - set - { + set { this.EnsureNotLocked(); ValidateName(value); originalName = value; @@ -349,7 +337,8 @@ public string OriginalName /// public Type ValueType { - [DebuggerStepThrough] get => valueType; + [DebuggerStepThrough] + get => valueType; [DebuggerStepThrough] set { this.EnsureNotLocked(); @@ -368,8 +357,7 @@ public Type ItemType [DebuggerStepThrough] get { return itemType; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); itemType = value; } @@ -383,8 +371,7 @@ public int? Length [DebuggerStepThrough] get { return length; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); length = value; } @@ -398,8 +385,7 @@ public int? Scale [DebuggerStepThrough] get { return scale; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); scale = value; } @@ -413,8 +399,7 @@ public int? Precision [DebuggerStepThrough] get { return precision; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); precision = value; } @@ -429,8 +414,7 @@ public object DefaultValue [DebuggerStepThrough] get { return defaultValue; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); defaultValue = value; } @@ -446,8 +430,7 @@ public string DefaultSqlExpression [DebuggerStepThrough] get { return defaultSqlExpression; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); defaultSqlExpression = value; } @@ -461,7 +444,7 @@ public string DefaultSqlExpression /// /// Gets for current field. /// - public Segment MappingInfo => mappingInfo; + public ref Segment MappingInfo => ref mappingInfo; /// /// Gets the underlying system property. @@ -471,8 +454,7 @@ public PropertyInfo UnderlyingProperty [DebuggerStepThrough] get { return underlyingProperty; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); underlyingProperty = value; } @@ -494,8 +476,7 @@ public FieldInfo Parent [DebuggerStepThrough] get { return parent; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); ArgumentValidator.EnsureArgumentNotNull(value, "Parent"); parent = value; @@ -519,8 +500,7 @@ public TypeInfo ReflectedType [DebuggerStepThrough] get { return reflectedType; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); reflectedType = value; } @@ -534,8 +514,7 @@ public TypeInfo DeclaringType [DebuggerStepThrough] get { return declaringType; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); declaringType = value; } @@ -554,8 +533,7 @@ public ColumnInfo Column [DebuggerStepThrough] get { return column; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); column = value; } @@ -567,10 +545,10 @@ public ColumnInfo Column /// public AssociationInfo GetAssociation(TypeInfo targetType) { - if (associations.Count==0) + if (associations.Count == 0) return null; - if (associations.Count==1) + if (associations.Count == 1) return associations[0]; var ordered = IsLocked @@ -594,8 +572,7 @@ public int AdapterIndex [DebuggerStepThrough] get { return adapterIndex; } [DebuggerStepThrough] - set - { + set { this.EnsureNotLocked(); adapterIndex = value; } @@ -608,8 +585,7 @@ public int AdapterIndex public IList Validators { get { return validators; } - internal set - { + internal set { this.EnsureNotLocked(); validators = value; } @@ -635,7 +611,7 @@ public bool HasValidators /// /// The tuple to extract value from. /// instance with the extracted value. - public Tuple ExtractValue (Tuple tuple) + public Tuple ExtractValue(Tuple tuple) { return valueExtractor.Apply(TupleTransformType.TransformedTuple, tuple); } @@ -643,7 +619,8 @@ public Tuple ExtractValue (Tuple tuple) /// /// Gets field columns. /// - public ColumnInfoCollection Columns { + public ColumnInfoCollection Columns + { get { if (columns != null) return columns; @@ -671,8 +648,8 @@ private void GetColumns(ColumnInfoCollection result) result.Add(Column); else if (!IsPrimitive) - foreach (var item in Fields.Where(f => f.Column!=null).Select(f => f.Column)) - result.Add(item); + foreach (var item in Fields.Where(f => f.Column != null).Select(f => f.Column)) + result.Add(item); } /// @@ -681,7 +658,7 @@ public override void UpdateState() base.UpdateState(); Fields.UpdateState(); - if (column!=null) + if (column != null) column.UpdateState(); columns = new ColumnInfoCollection(this, "Columns"); GetColumns(columns); @@ -699,7 +676,7 @@ public override void Lock(bool recursive) return; validators = new ReadOnlyList(validators.ToList()); Fields.Lock(true); - if (column!=null) + if (column != null) column.Lock(true); if (associations.Count > 1) { var sorted = associations.Reorder(); @@ -711,12 +688,12 @@ public override void Lock(bool recursive) private void CreateMappingInfo() { - if (column!=null) { + if (column != null) { if (reflectedType.IsStructure) mappingInfo = new Segment(reflectedType.Columns.IndexOf(column), 1); else { var primaryIndex = reflectedType.Indexes.PrimaryIndex; - var indexColumn = primaryIndex.Columns.Where(c => c.Name==column.Name).FirstOrDefault(); + var indexColumn = primaryIndex.Columns.Where(c => c.Name == column.Name).FirstOrDefault(); if (indexColumn == null) throw new InvalidOperationException(); mappingInfo = new Segment(primaryIndex.Columns.IndexOf(indexColumn), 1); @@ -753,7 +730,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(this, obj)) return true; - if (obj.GetType()!=typeof (FieldInfo)) + if (obj.GetType() != typeof(FieldInfo)) return false; return Equals((FieldInfo) obj); } @@ -776,10 +753,10 @@ public override int GetHashCode() private int CalculateHashCode() { unchecked { - return - (declaringType.GetHashCode() * 397) ^ - (valueType.GetHashCode() * 631) ^ - Name.GetHashCode(); + return + (declaringType.GetHashCode() * 397) ^ + (valueType.GetHashCode() * 631) ^ + Name.GetHashCode(); } } @@ -798,22 +775,21 @@ object ICloneable.Clone() /// public FieldInfo Clone() { - var clone= new FieldInfo(declaringType, reflectedType, Attributes) - { - Name = Name, - OriginalName = OriginalName, - MappingName = MappingName, - underlyingProperty = underlyingProperty, - valueType = valueType, - itemType = itemType, - length = length, - scale = scale, - precision = precision, - defaultValue = defaultValue, - defaultSqlExpression = defaultSqlExpression, - DeclaringField = DeclaringField, - Validators = Validators.Select(v => v.CreateNew()).ToList(), - }; + var clone = new FieldInfo(declaringType, reflectedType, Attributes) { + Name = Name, + OriginalName = OriginalName, + MappingName = MappingName, + underlyingProperty = underlyingProperty, + valueType = valueType, + itemType = itemType, + length = length, + scale = scale, + precision = precision, + defaultValue = defaultValue, + defaultSqlExpression = defaultSqlExpression, + DeclaringField = DeclaringField, + Validators = Validators.Select(v => v.CreateNew()).ToList(), + }; clone.Associations.AddRange(associations); return clone; } @@ -839,8 +815,8 @@ private FieldInfo(TypeInfo declaringType, TypeInfo reflectedType, FieldAttribute Attributes = attributes; this.declaringType = declaringType; this.reflectedType = reflectedType; - Fields = IsEntity || IsStructure - ? new FieldInfoCollection(this, "Fields") + Fields = IsEntity || IsStructure + ? new FieldInfoCollection(this, "Fields") : FieldInfoCollection.Empty; associations = new NodeCollection(this, "Associations"); } diff --git a/Orm/Xtensive.Orm/Orm/Persistent.cs b/Orm/Xtensive.Orm/Orm/Persistent.cs index fc8deb274f..f0372d499f 100644 --- a/Orm/Xtensive.Orm/Orm/Persistent.cs +++ b/Orm/Xtensive.Orm/Orm/Persistent.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2020 Xtensive LLC. +// Copyright (C) 2007-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Dmitri Maximov @@ -85,12 +85,12 @@ public T GetProperty(string fieldName) var pair = fieldName.RevertibleSplitFirstAndTail(';', '.'); var field = TypeInfo.Fields[pair.First]; // TODO: Improve (use DelegateHelper) - if (field.UnderlyingProperty!=null) { + if (field.UnderlyingProperty != null) { var mi = field.UnderlyingProperty.GetGetMethod(true); if (mi == null && field.UnderlyingProperty.ReflectedType != field.UnderlyingProperty.DeclaringType) { - var p = field.UnderlyingProperty; + var p = field.UnderlyingProperty; var dt = p.DeclaringType; - mi = dt.GetProperty(p.Name, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic).GetGetMethod(true); + mi = dt.GetProperty(p.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetGetMethod(true); } value = mi.Invoke(this, null); } @@ -123,14 +123,14 @@ public void SetProperty(string fieldName, T value) if (field.UnderlyingProperty != null) { var mi = field.UnderlyingProperty.GetSetMethod(true); if (mi == null && field.UnderlyingProperty.ReflectedType != field.UnderlyingProperty.DeclaringType) { - var p = field.UnderlyingProperty; + var p = field.UnderlyingProperty; var dt = p.DeclaringType; - mi = dt.GetProperty(p.Name, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic).GetSetMethod(true); + mi = dt.GetProperty(p.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetSetMethod(true); } - mi.Invoke(this, new object[]{value}); + mi.Invoke(this, new object[] { value }); } else - SetFieldValue(pair.First, (object)value); // Untyped, since T might be wrong + SetFieldValue(pair.First, (object) value); // Untyped, since T might be wrong } else { var persistent = GetProperty(pair.First); @@ -144,7 +144,7 @@ public void SetProperty(string fieldName, T value) /// /// Gets the field value. - /// Field value type must be specified precisely. + /// Field value type must be specified precisely. /// E.g. usage of instead of might lead to unpredictable effects. /// /// Field value type. @@ -167,7 +167,7 @@ protected internal object GetFieldValue(string fieldName) /// /// Gets the field value. - /// Field value type must be specified precisely. + /// Field value type must be specified precisely. /// E.g. usage of instead of might lead to unpredictable effects. /// /// Field value type. @@ -187,7 +187,7 @@ protected internal T GetFieldValue(FieldInfo field) SystemGetValueCompleted(field, result, null); return result; } - catch(Exception e) { + catch (Exception e) { SystemGetValueCompleted(field, result, e); throw; } @@ -212,21 +212,21 @@ protected internal object GetFieldValue(FieldInfo field) SystemGetValueCompleted(field, result, null); return result; } - catch(Exception e) { + catch (Exception e) { SystemGetValueCompleted(field, result, e); throw; } } /// - /// Gets the key of the entity, that is referenced by specified field + /// Gets the key of the entity, that is referenced by specified field /// of the target persistent object. /// /// - /// Result is the same as GetValue<Entity>(field).Key, + /// Result is the same as GetValue<Entity>(field).Key, /// but referenced entity will not be materialized. /// - /// The reference field. Field value type must be + /// The reference field. Field value type must be /// descendant. /// Referenced entity key. /// Field is not a reference field. @@ -265,7 +265,7 @@ protected internal Key GetReferenceKey(FieldInfo field) SystemGetValueCompleted(field, key, null); return key; } - catch(Exception e) { + catch (Exception e) { SystemGetValueCompleted(field, key, e); throw; } @@ -292,15 +292,19 @@ protected internal void SetReferenceKey(FieldInfo field, Key value) string.Format(Strings.ExFieldIsNotAnEntityField, field.Name, field.ReflectedType.Name)); } - if (!isPersisting) { SystemBeforeTupleChange(); } + if (!isPersisting) { + SystemBeforeTupleChange(); + } - var types = Session.Domain.Model.Types; + var fieldMappingInfo = field.MappingInfo; if (value == null) { - for (var i = 0; i < field.MappingInfo.Length; i++) { - Tuple.SetValue(field.MappingInfo.Offset + i, null); + for (var i = 0; i < fieldMappingInfo.Length; i++) { + Tuple.SetValue(fieldMappingInfo.Offset + i, null); } - if (!isPersisting) { SystemTupleChange(); } + if (!isPersisting) { + SystemTupleChange(); + } return; } if (!field.ValueType.IsAssignableFrom(value.TypeInfo.UnderlyingType)) { @@ -311,9 +315,9 @@ protected internal void SetReferenceKey(FieldInfo field, Key value) return; } - value.Value.CopyTo(Tuple, 0, field.MappingInfo.Offset, field.MappingInfo.Length); + value.Value.CopyTo(Tuple, 0, fieldMappingInfo.Offset, fieldMappingInfo.Length); if (field.IsPrimaryKey) { - value.Value.CopyTo(((Entity) this).Key.Value, 0, field.MappingInfo.Offset, field.MappingInfo.Length); + value.Value.CopyTo(((Entity)this).Key.Value, 0, fieldMappingInfo.Offset, fieldMappingInfo.Length); } if (!isPersisting) { @@ -331,7 +335,7 @@ protected internal void SetReferenceKey(FieldInfo field, Key value) /// /// Sets the field value. - /// Field value type must be specified precisely. + /// Field value type must be specified precisely. /// E.g. usage of instead of might lead to unpredictable effects. /// /// Field value type. @@ -354,7 +358,7 @@ protected internal void SetFieldValue(string fieldName, object value) /// /// Sets the field value. - /// Field value type must be specified precisely. + /// Field value type must be specified precisely. /// E.g. usage of instead of might lead to unpredictable effects. /// /// Field value type. @@ -369,7 +373,7 @@ protected internal void SetFieldValue(FieldInfo field, T value) /// /// Sets the field value. - /// Field value type must be specified precisely. + /// Field value type must be specified precisely. /// E.g. usage of instead of might lead to unpredictable effects. /// /// The field. @@ -398,11 +402,11 @@ internal void SetFieldValue(FieldInfo field, object value, SyncContext syncConte var scope = operations.BeginRegistration(Operations.OperationType.System); try { var entity = this as Entity; - if (entity!=null) { + if (entity != null) { if (operations.CanRegisterOperation) operations.RegisterOperation(new EntityFieldSetOperation(entity.Key, field, value)); var entityValue = value as IEntity; - if (entityValue!=null) { + if (entityValue != null) { var valueKey = entityValue.Key; Session.ReferenceFieldsChangesRegistry.Register(entity.Key, valueKey, field); } @@ -411,24 +415,24 @@ internal void SetFieldValue(FieldInfo field, object value, SyncContext syncConte var persistent = this; var currentField = field; var structure = persistent as Structure; - while (structure!=null && structure.Owner!=null) { + while (structure != null && structure.Owner != null) { var pair = new Pair(structure.Field, currentField); currentField = structure.Owner.TypeInfo.StructureFieldMapping[pair]; persistent = structure.Owner; structure = persistent as Structure; } entity = persistent as Entity; - if (entity!=null) { + if (entity != null) { if (operations.CanRegisterOperation) operations.RegisterOperation(new EntityFieldSetOperation(entity.Key, currentField, value)); var entityValue = value as IEntity; - if (entityValue!=null) { + if (entityValue != null) { var valueKey = entityValue.Key; Session.ReferenceFieldsChangesRegistry.Register(entity.Key, valueKey, field); } } } - + if (fieldAccessor.AreSameValues(oldValue, value)) { operations.NotifyOperationStarting(false); scope.Complete(); @@ -441,13 +445,13 @@ internal void SetFieldValue(FieldInfo field, object value, SyncContext syncConte entity = value as Entity ?? oldValue as Entity; if (entity != null) association = field.GetAssociation(entity.TypeInfo); - if (association!=null && association.IsPaired) { + if (association != null && association.IsPaired) { Key currentKey = GetReferenceKey(field); Key newKey = null; var newReference = (Entity) (object) value; - if (newReference!=null) + if (newReference != null) newKey = newReference.Key; - if (currentKey!=newKey) { + if (currentKey != newKey) { Session.PairSyncManager.ProcessRecursively(syncContext, removalContext, OperationType.Set, association, (Entity) this, newReference, () => { SystemBeforeTupleChange(); @@ -457,7 +461,7 @@ internal void SetFieldValue(FieldInfo field, object value, SyncContext syncConte } } else { - // The method of Equals(object, object) wrapped with in a block 'try catch', + // The method of Equals(object, object) wrapped with in a block 'try catch', // because that for data types NpgsqlPath and NpgsqlPolygon which are defined without an initial value it works incorrectly. bool canBeEqual; try { @@ -474,7 +478,7 @@ internal void SetFieldValue(FieldInfo field, object value, SyncContext syncConte } } - if (removalContext!=null) { + if (removalContext != null) { // Postponing finalizers (events) removalContext.EnqueueFinalizer(() => { try { @@ -501,7 +505,7 @@ internal void SetFieldValue(FieldInfo field, object value, SyncContext syncConte scope.Complete(); } finally { - if (removalContext==null) + if (removalContext == null) scope.DisposeSafely(); } } @@ -605,7 +609,7 @@ protected virtual void OnSetFieldValue(FieldInfo field, object oldValue, object /// public override void OnValidate() /// { /// base.OnValidate(); - /// if (Age <= 0) + /// if (Age <= 0) /// throw new InvalidOperationException("Age should be positive."); /// } /// @@ -699,7 +703,7 @@ protected internal void NotifyPropertyChanged(string propertyName) { var subscription = GetSubscription(EntityEventBroker.PropertyChangedEventKey); if (subscription.Second != null) { - ((PropertyChangedEventHandler)subscription.Second) + ((PropertyChangedEventHandler) subscription.Second) .Invoke(this, new PropertyChangedEventArgs(propertyName)); } } @@ -718,24 +722,22 @@ protected internal void NotifyPropertyChanged(string propertyName) /// string IDataErrorInfo.this[string columnName] { - get - { + get { if (!CanBeValidated) return string.Empty; var result = GetValidationResult(columnName); - return result!=null ? result.ErrorMessage : string.Empty; + return result != null ? result.ErrorMessage : string.Empty; } } /// string IDataErrorInfo.Error { - get - { + get { if (!CanBeValidated) return string.Empty; var result = GetValidationResult(); - return result!=null ? result.ErrorMessage : string.Empty; + return result != null ? result.ErrorMessage : string.Empty; } } @@ -754,7 +756,7 @@ internal IFieldValueAdapter GetFieldValueAdapter(FieldInfo field, Func f.AdapterIndex).Max(); fieldAdapters = new IFieldValueAdapter[maxAdapterIndex + 1]; } @@ -797,18 +799,18 @@ internal PersistentFieldState GetFieldState(FieldInfo field) { if (field.ReflectedType.IsInterface) field = TypeInfo.FieldMap[field]; - if (field.ReflectedType!=TypeInfo) + if (field.ReflectedType != TypeInfo) throw new ArgumentException(Strings.ExFieldBelongsToADifferentType, "field"); var mappingInfo = field.MappingInfo; - if (mappingInfo.Length==0) + if (mappingInfo.Length == 0) return 0; // EntitySet or another proxy PersistentFieldState state = 0; var tuple = Tuple; - if (tuple!=null && tuple.AreAllColumnsAvalilable(mappingInfo)) + if (tuple != null && tuple.AreAllColumnsAvalilable(mappingInfo)) state = PersistentFieldState.Loaded; var diffTuple = tuple as DifferentialTuple; - if (diffTuple!=null && diffTuple.Difference.IsAtLeastOneColumAvailable(mappingInfo)) + if (diffTuple != null && diffTuple.Difference.IsAtLeastOneColumAvailable(mappingInfo)) state = PersistentFieldState.Modified; return state; } diff --git a/Orm/Xtensive.Orm/Orm/Session.Cache.cs b/Orm/Xtensive.Orm/Orm/Session.Cache.cs index 784c0ae6bc..808b7d0795 100644 --- a/Orm/Xtensive.Orm/Orm/Session.Cache.cs +++ b/Orm/Xtensive.Orm/Orm/Session.Cache.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2008-2020 Xtensive LLC. +// Copyright (C) 2008-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alex Yakunin @@ -21,6 +21,8 @@ namespace Xtensive.Orm { public partial class Session { + private static readonly Converter keyExtractor = i => i.Key; + // EntitySets with cached items that filled their cache // within DisableSaveChanges() scope. private HashSet entitySetsWithInvalidState; @@ -44,7 +46,7 @@ private void InvalidateCachedEntities() foreach (var state in EntityStateCache) { var entity = state.TryGetEntity(); // Invalidate any entity sets - if (entity!=null && state.IsActual) // Don't bother invalidating non-actual entities + if (entity != null && state.IsActual) // Don't bother invalidating non-actual entities foreach (var field in entity.TypeInfo.Fields.Where(f => f.IsEntitySet)) { var entitySet = (EntitySetBase) entity.GetFieldAccessor(field).GetUntypedValue(entity); ((IInvalidatable) entitySet.State).Invalidate(); @@ -65,7 +67,7 @@ internal void RemapEntityKeys(KeyMapping keyMapping) => private async ValueTask RemapEntityKeys(KeyMapping keyMapping, bool isAsync, CancellationToken token = default) { - if (keyMapping.Map.Count==0) + if (keyMapping.Map.Count == 0) return; using (Activate()) { if (!LazyKeyGenerationIsEnabled) { @@ -79,7 +81,7 @@ private async ValueTask RemapEntityKeys(KeyMapping keyMapping, bool isAsync, Can foreach (var entityState in EntityChangeRegistry.GetItems(PersistenceState.New)) { var key = entityState.Key; var remappedKey = keyMapping.TryRemapKey(key); - if (remappedKey!=key) + if (remappedKey != key) entityState.RemapKey(remappedKey); EntityStateCache.Add(entityState); } @@ -104,7 +106,7 @@ internal Entity CreateOrInitializeExistingEntity(Type type, Key key) { var state = CreateEntityState(key, false); var entity = state.TryGetEntity(); - if (entity==null) + if (entity == null) return Activator.CreateEntity(this, type, state); else { InitializeEntity(entity, false); @@ -116,8 +118,8 @@ internal void RemoveOrCreateRemovedEntity(Type type, Key key, EntityRemoveReason { // Checking for deleted entity with the same key var result = EntityStateCache[key, false]; - if (result!=null) { - if (result.PersistenceState==PersistenceState.Removed) { + if (result != null) { + if (result.PersistenceState == PersistenceState.Removed) { return; } result.Entity.RemoveLaterInternal(reason); @@ -153,7 +155,7 @@ internal EntityState CreateEntityState(Key key, bool failIfStateIsAlreadyBound) var result = EntityStateCache[key, false]; EnforceChangeRegistrySizeLimit(); // Must be done before new entity registration - // If type is unknown, we consider tuple is null, + // If type is unknown, we consider tuple is null, // so its Entity is considered as non-existing Tuple tuple = null; if (key.HasExactType) { @@ -162,14 +164,14 @@ internal EntityState CreateEntityState(Key key, bool failIfStateIsAlreadyBound) tuple = typeInfo.CreateEntityTuple(key.Value, StorageNode.TypeIdRegistry[typeInfo]); } - if (result==null) { + if (result == null) { result = new EntityState(this, key, tuple) { PersistenceState = PersistenceState.New }; EntityStateCache.Add(result); } else { - if (result.Entity!=null && !result.Entity.IsRemoved && failIfStateIsAlreadyBound) + if (result.Entity != null && !result.Entity.IsRemoved && failIfStateIsAlreadyBound) throw new UniqueConstraintViolationException(string.Format(Strings.ExEntityWithKeyXAlreadyExists, key)); result.Key = key; result.Tuple = tuple; @@ -191,9 +193,9 @@ internal bool LookupStateInCache(Key key, out EntityState entityState) internal bool LookupStateInCache(Key key, FieldInfo fieldInfo, out EntitySetState entitySetState) { var entityState = EntityStateCache[key, false]; - if (entityState!=null) { + if (entityState != null) { var entity = entityState.Entity; - if (entity!=null) { + if (entity != null) { var entitySet = (EntitySetBase) entity.GetFieldValue(fieldInfo); if (entitySet.CheckStateIsLoaded()) { entitySetState = entitySet.State; @@ -211,8 +213,8 @@ internal bool LookupStateInCache(Key key, FieldInfo fieldInfo, out EntitySetStat internal EntityState UpdateStateInCache(Key key, Tuple tuple, bool isStale) { var result = EntityStateCache[key, true]; - if (result==null) { - if (!key.HasExactType && tuple!=null) + if (result == null) { + if (!key.HasExactType && tuple != null) throw Exceptions.InternalError( Strings.ExCannotAssociateNonEmptyEntityStateWithKeyOfUnknownType, OrmLog.Instance); @@ -243,10 +245,10 @@ internal EntitySetState UpdateStateInCache(Key key, FieldInfo fieldInfo, IEnumer bool isFullyLoaded) { var entityState = EntityStateCache[key, true]; - if (entityState==null) + if (entityState == null) return null; var entity = entityState.Entity; - if (entity==null) + if (entity == null) return null; var entitySet = (EntitySetBase) entity.GetFieldValue(fieldInfo); return entitySet.UpdateState(entityKeys, isFullyLoaded); @@ -284,12 +286,12 @@ private void InvalidateEntitySetsWithInvalidState() private static ICache CreateSessionCache(SessionConfiguration configuration) { switch (configuration.CacheType) { - case SessionCacheType.Infinite: - return new InfiniteCache(configuration.CacheSize, i => i.Key); - default: - return new LruCache( - configuration.CacheSize, i => i.Key, - new WeakCache(false, i => i.Key)); + case SessionCacheType.Infinite: + return new InfiniteCache(configuration.CacheSize, keyExtractor); + default: + return new LruCache( + configuration.CacheSize, keyExtractor, + new WeakCache(false, keyExtractor)); } } } diff --git a/Orm/Xtensive.Orm/Orm/Session.cs b/Orm/Xtensive.Orm/Orm/Session.cs index afed810be3..1f1a37a878 100644 --- a/Orm/Xtensive.Orm/Orm/Session.cs +++ b/Orm/Xtensive.Orm/Orm/Session.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2020 Xtensive LLC. +// Copyright (C) 2007-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Dmitri Maximov @@ -37,24 +37,24 @@ namespace Xtensive.Orm /// /// /// - /// Each session maintains its own connection to the database and + /// Each session maintains its own connection to the database and /// caches a set of materialized persistent instates. /// /// /// Session implements interface, that means each Session /// can be either active or not active in a particular thread (see property). - /// Each thread can contain only one active session in each point of time, such session - /// can be a accessed via Session.Current property + /// Each thread can contain only one active session in each point of time, such session + /// can be a accessed via Session.Current property /// or Session.Demand() method. /// /// - /// Sessions are opened (and, optionally, activated) by - /// Domain.OpenSession() method. + /// Sessions are opened (and, optionally, activated) by + /// Domain.OpenSession() method. /// Existing session can be activated by method. /// /// /// - /// /// /// @@ -62,13 +62,19 @@ namespace Xtensive.Orm [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] public partial class Session : DomainBound, IVersionSetProvider, - IContext, + IContext, IHasExtensions, IDisposable, IAsyncDisposable { private const string IdentifierFormat = "#{0}"; - private const string FullNameFormat = "{0}, #{1}"; + private const string FullNameFormat = "{0}, #{1}"; + + private static readonly Type + typeofSession = typeof(Session), + typeofSessionConfiguration = typeof(SessionConfiguration), + typeofSessionHandler = typeof(SessionHandler), + typeofServiceContainer = typeof(ServiceContainer); private static Func resolver; private static long lastUsedIdentifier; @@ -110,9 +116,9 @@ public partial class Session : DomainBound, /// Gets a value indicating whether session is disconnected: /// session supports non-transactional entity states and does not support autosaving of changes. /// - public bool IsDisconnected { - get - { + public bool IsDisconnected + { + get { return Configuration.Supports(SessionOptions.NonTransactionalEntityStates) && !Configuration.Supports(SessionOptions.AutoSaveChanges); } @@ -122,7 +128,7 @@ public bool IsDisconnected { /// Indicates whether lazy generation of keys is enabled. /// internal bool LazyKeyGenerationIsEnabled { get { return Configuration.Supports(SessionOptions.LazyKeyGeneration); } } - + /// /// Gets the operations registry of this . /// @@ -136,8 +142,7 @@ public bool IsDisconnected { public int? CommandTimeout { get { return commandTimeout; } - set - { + set { if (Handler != null) Handler.SetCommandTimeout(value); commandTimeout = value; @@ -150,13 +155,11 @@ public int? CommandTimeout /// public ConnectionInfo ConnectionInfo { - get - { + get { var directSqlService = Services.Demand(); return directSqlService.ConnectionInfo; } - set - { + set { var directSqlService = Services.Demand(); directSqlService.ConnectionInfo = value; } @@ -175,9 +178,8 @@ public string StorageNodeId /// public StorageNode StorageNode { - get - { - if (storageNode==null) + get { + if (storageNode == null) SetStorageNode(Handlers.StorageNodeRegistry.Get(WellKnown.DefaultNodeId)); return storageNode; } @@ -188,11 +190,12 @@ public StorageNode StorageNode /// when there is no active . /// /// - /// The setter of this property can be invoked just once per application lifetime; + /// The setter of this property can be invoked just once per application lifetime; /// assigned resolver can not be changed. /// /// Resolver is already assigned. - public static Func Resolver { + public static Func Resolver + { [DebuggerStepThrough] get { return resolver; @@ -294,9 +297,9 @@ private EnumerationContextOptions GetEnumerationContextOptions() private IServiceContainer CreateSystemServices() { var registrations = new List{ - new ServiceRegistration(typeof (Session), this), - new ServiceRegistration(typeof (SessionConfiguration), Configuration), - new ServiceRegistration(typeof (SessionHandler), Handler), + new ServiceRegistration(typeofSession, this), + new ServiceRegistration(typeofSessionConfiguration, Configuration), + new ServiceRegistration(typeofSessionHandler, Handler), }; Handler.AddSystemServices(registrations); return new ServiceContainer(registrations, Domain.Services); @@ -304,8 +307,8 @@ private IServiceContainer CreateSystemServices() private IServiceContainer CreateServices() { - var userContainerType = Configuration.ServiceContainerType ?? typeof (ServiceContainer); - var registrations = Domain.Configuration.Types.SessionServices.SelectMany(ServiceRegistration.CreateAll); + var userContainerType = Configuration.ServiceContainerType ?? typeofServiceContainer; + var registrations = Domain.Configuration.Types.ServiceRegistrations; var systemContainer = CreateSystemServices(); var userContainer = ServiceContainer.Create(userContainerType, systemContainer); return new ServiceContainer(registrations, userContainer); @@ -313,7 +316,7 @@ private IServiceContainer CreateServices() internal void SetStorageNode(StorageNode node) { - if (storageNode!=null) + if (storageNode != null) throw new InvalidOperationException(Strings.ExStorageNodeIsAlreadySelected); Handler.SetStorageNode(node); storageNode = node; @@ -342,17 +345,18 @@ internal ExecutableProvider Compile(CompilableProvider provider, CompilerConfigu /// /// Gets the current active instance. /// - public static Session Current { + public static Session Current + { [DebuggerStepThrough] get { return - SessionScope.CurrentSession ?? (resolver==null ? null : resolver.Invoke()); + SessionScope.CurrentSession ?? (resolver == null ? null : resolver.Invoke()); } } /// - /// Gets the current , - /// or throws , + /// Gets the current , + /// or throws , /// if active is not found. /// /// Current session. @@ -360,20 +364,20 @@ public static Session Current { public static Session Demand() { var currentSession = Current; - if (currentSession==null) + if (currentSession == null) throw new InvalidOperationException(Strings.ExActiveSessionIsRequiredForThisOperation); return currentSession; } /// - public bool IsActive { get { return Current==this; } } + public bool IsActive { get { return Current == this; } } /// public SessionScope Activate() { var currentSession = SessionScope.CurrentSession; // Not Session.Current - // to avoid possible comparison with Session provided by Session.Resolver. - return currentSession==this ? null : new SessionScope(this); + return currentSession == this ? null : new SessionScope(this); } @@ -382,7 +386,7 @@ public SessionScope Activate() /// See for more detailed explanation /// of purpose of this method. /// - /// If set to , + /// If set to , /// is thrown if another session is active, and /// either this or active session does not have flag. /// A disposable object reverting the action. @@ -393,11 +397,11 @@ public SessionScope Activate(bool checkSwitching) return Activate(); var currentSession = SessionScope.CurrentSession; // Not Session.Current - // to avoid possible comparison with Session provided by Session.Resolver. - if (currentSession==null) + if (currentSession == null) return new SessionScope(this); - if (currentSession==this) + if (currentSession == this) return null; - if (currentSession.Transaction==null || (allowSwitching && currentSession.allowSwitching)) + if (currentSession.Transaction == null || (allowSwitching && currentSession.allowSwitching)) return new SessionScope(this); throw new InvalidOperationException( string.Format(Strings.ExAttemptToAutomaticallyActivateSessionXInsideSessionYIsBlocked, this, currentSession)); @@ -411,7 +415,7 @@ public SessionScope Activate(bool checkSwitching) /// A disposable object reverting the action. public static SessionScope Deactivate() { - return SessionScope.CurrentSession==null + return SessionScope.CurrentSession == null ? null : new SessionScope(null); } @@ -427,9 +431,10 @@ IDisposable IContext.Activate() #region IHasExtensions members /// - public IExtensionCollection Extensions { + public IExtensionCollection Extensions + { get { - if (extensions==null) + if (extensions == null) extensions = new ExtensionCollection(); return extensions; } @@ -515,12 +520,12 @@ private SessionHandler CreateSessionHandler() var transactionIsExternal = false; var upgradeContext = UpgradeContext.GetCurrent(Domain.UpgradeContextCookie); - if (upgradeContext!=null) { + if (upgradeContext != null) { connection = upgradeContext.Services.Connection; connectionIsExternal = true; transactionIsExternal = true; } - else if (Domain.SingleConnection!=null) { + else if (Domain.SingleConnection != null) { connection = Domain.SingleConnection; connectionIsExternal = true; } diff --git a/Orm/Xtensive.Orm/Reflection/AttributeHelper.cs b/Orm/Xtensive.Orm/Reflection/AttributeHelper.cs index 905c116c1c..48799c2a1c 100644 --- a/Orm/Xtensive.Orm/Reflection/AttributeHelper.cs +++ b/Orm/Xtensive.Orm/Reflection/AttributeHelper.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2008-2020 Xtensive LLC. +// Copyright (C) 2008-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alex Yakunin @@ -6,10 +6,11 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Linq; using System.Reflection; -using Xtensive.Collections; -using Xtensive.Core; - +using AttributesKey = System.ValueTuple; +using PerAttributeKey = System.ValueTuple; namespace Xtensive.Reflection { @@ -18,37 +19,14 @@ namespace Xtensive.Reflection /// public static class AttributeHelper { - /// - /// A shortcut to method. - /// This method does not inherit the attribute. - /// - /// The type of attribute to get. - /// Member to get attributes of. - /// An attribute of specified type, or , if none. - public static TAttribute GetAttribute(this MemberInfo member) - where TAttribute: Attribute + private static class AttributeDictionary where TAttribute : Attribute { - var attributes = member.GetCustomAttributes(typeof (TAttribute), false); - if (attributes.Length==0) - return null; - if (attributes.Length>1) - throw new InvalidOperationException(string.Format(Strings.ExMultipleAttributesOfTypeXAreNotAllowedHere, - member.GetShortName(true), - typeof (TAttribute).GetShortName())); - return (TAttribute) attributes[0]; + public static readonly ConcurrentDictionary Dictionary + = new ConcurrentDictionary(); } - /// - /// A shortcut to method. - /// This method does not inherit the attribute. - /// - /// The type of attribute to get. - /// Member to get attributes of. - /// An array of attributes of specified type. - public static TAttribute[] GetAttributes(this MemberInfo member) - { - return member.GetCustomAttributes(typeof (TAttribute), false).Cast(); - } + private static readonly ConcurrentDictionary attributesByMemberInfoAndSearchOptions + = new ConcurrentDictionary(); /// /// A shortcut to method. @@ -57,41 +35,16 @@ public static TAttribute[] GetAttributes(this MemberInfo member) /// Member to get attributes of. /// Attribute search options. /// An array of attributes of specified type. - public static TAttribute[] GetAttributes(this MemberInfo member, AttributeSearchOptions options) - where TAttribute: Attribute - { - if (options==AttributeSearchOptions.InheritNone) - return member.GetAttributes(); - var attributes = member.GetCustomAttributes(typeof (TAttribute), false).Cast(); - if (attributes.Length==0) { - if ((options & AttributeSearchOptions.InheritFromPropertyOrEvent)!=0) { - var m = member as MethodInfo; - if (m!=null) { - var poe = (MemberInfo) m.GetProperty() ?? m.GetEvent(); - if (poe!=null) - attributes = poe.GetAttributes(); - } - } - if ((options & AttributeSearchOptions.InheritFromBase)!=0 && - (options & AttributeSearchOptions.InheritFromAllBase)==0) { - var bm = member.GetBaseMember(); - if (bm!=null) - attributes = attributes.Combine(bm.GetAttributes(options)); - } - } - - if ((options & AttributeSearchOptions.InheritFromAllBase)!=0 - && member.DeclaringType!=WellKnownTypes.Object) { - var bm = member.GetBaseMember(); - if (bm!=null) - attributes = attributes.Combine(bm.GetAttributes(options)); - } - - return attributes; - } + /// + public static TAttribute[] GetAttributes(this MemberInfo member, AttributeSearchOptions options = AttributeSearchOptions.InheritNone) + where TAttribute : Attribute => + AttributeDictionary.Dictionary.GetOrAdd( + new PerAttributeKey(member, options), + key => GetAttributes(key.Item1, typeof(TAttribute), key.Item2).Cast().ToArray() + ); /// - /// A version of + /// A version of /// returning just one attribute. /// /// The type of attribute to get. @@ -102,19 +55,61 @@ public static TAttribute[] GetAttributes(this MemberInfo member, Att /// throws , if there is more then one attribute of specified type found. /// /// Thrown if there is more then one attribute of specified type found. - public static TAttribute GetAttribute(this MemberInfo member, AttributeSearchOptions options) - where TAttribute: Attribute + public static TAttribute GetAttribute(this MemberInfo member, AttributeSearchOptions options = AttributeSearchOptions.InheritNone) + where TAttribute : Attribute { - if (options==AttributeSearchOptions.InheritNone) - return member.GetAttribute(); var attributes = member.GetAttributes(options); - if (attributes.Length==0) - return null; - if (attributes.Length>1) - throw new InvalidOperationException(string.Format(Strings.ExMultipleAttributesOfTypeXAreNotAllowedHere, + return attributes.Length switch { + 0 => null, + 1 => attributes[0], + _ => throw new InvalidOperationException(string.Format(Strings.ExMultipleAttributesOfTypeXAreNotAllowedHere, member.GetShortName(true), - typeof(TAttribute).GetShortName())); - return attributes[0]; + typeof(TAttribute).GetShortName())) + }; + } + + private static Attribute[] GetAttributes(MemberInfo member, Type attributeType, AttributeSearchOptions options) => + attributesByMemberInfoAndSearchOptions.GetOrAdd( + new AttributesKey(member, attributeType, options), + t => ExtractAttributes(t).ToArray() + ); + + private static Attribute[] GetAttributes(this MemberInfo member, Type attributeType) + { + var attrObjects = member.GetCustomAttributes(attributeType, false); + var attrs = new Attribute[attrObjects.Length]; + for (int i = attrObjects.Length; i-- > 0;) { + attrs[i] = (Attribute) attrObjects[i]; + } + return attrs; + } + + private static IEnumerable ExtractAttributes((MemberInfo member, Type attributeType, AttributeSearchOptions options) t) { + (var member, var attributeType, var options) = t; + + var attributes = member.GetCustomAttributes(attributeType, false).Cast().ToList(); + if (options == AttributeSearchOptions.InheritNone) + return attributes; + if (attributes.Count == 0) { + if ((options & AttributeSearchOptions.InheritFromPropertyOrEvent) != 0 + && member is MethodInfo m + && ((MemberInfo) m.GetProperty() ?? m.GetEvent()) is MemberInfo poe) { + attributes = poe.GetAttributes(attributeType).ToList(); + } + if ((options & AttributeSearchOptions.InheritFromBase) != 0 + && (options & AttributeSearchOptions.InheritFromAllBase) == 0 + && member.GetBaseMember() is MemberInfo bm) { + attributes.AddRange(GetAttributes(bm, attributeType, options)); + } + } + + if ((options & AttributeSearchOptions.InheritFromAllBase) != 0 + && member.DeclaringType != WellKnownTypes.Object + && member.GetBaseMember() is MemberInfo bm2) { + attributes.AddRange(GetAttributes(bm2, attributeType, options)); + } + + return attributes; } } } diff --git a/Orm/Xtensive.Orm/Reflection/TypeHelper.cs b/Orm/Xtensive.Orm/Reflection/TypeHelper.cs index b1843edadc..e8432951db 100644 --- a/Orm/Xtensive.Orm/Reflection/TypeHelper.cs +++ b/Orm/Xtensive.Orm/Reflection/TypeHelper.cs @@ -20,7 +20,6 @@ using Xtensive.Sorting; - namespace Xtensive.Reflection { /// @@ -28,8 +27,26 @@ namespace Xtensive.Reflection /// public static class TypeHelper { + private class TypesEqualityComparer : IEqualityComparer<(Type, Type[])> + { + public bool Equals((Type, Type[]) x, (Type, Type[]) y) => + x.Item1 == y.Item1 && x.Item2.SequenceEqual(y.Item2); + + public int GetHashCode((Type, Type[]) obj) + { + var hash = obj.Item1.GetHashCode(); + for (int i = obj.Item2.Length; i-- > 0;) { + hash = HashCode.Combine(hash, obj.Item2[i]); + } + return hash; + } + } + private const string invokeMethodName = "Invoke"; + private static readonly ConcurrentDictionary<(Type, Type[]), ConstructorInfo> constructorInfoByTypes = + new ConcurrentDictionary<(Type, Type[]), ConstructorInfo>(new TypesEqualityComparer()); + private static readonly object emitLock = new object(); private static readonly int NullableTypeMetadataToken = WellKnownTypes.NullableOfT.MetadataToken; private static readonly Module NullableTypeModule = WellKnownTypes.NullableOfT.Module; @@ -144,13 +161,13 @@ private static T CreateAssociateInternal(Type originalForType, Type currentFo var rank = currentForType.GetArrayRank(); associateTypePrefix = rank == 1 ? "Array`1" : $"Array{rank}D`1"; - genericArguments = new[] {elementType}; + genericArguments = new[] { elementType }; } else if (currentForType == WellKnownTypes.Enum) { // Enum type var underlyingType = Enum.GetUnderlyingType(originalForType); associateTypePrefix = "Enum`2"; - genericArguments = new[] {originalForType, underlyingType}; + genericArguments = new[] { originalForType, underlyingType }; } else if (currentForType == WellKnownTypes.Array) { // Untyped Array type @@ -310,7 +327,7 @@ private static T CreateAssociateInternal(Type originalForType, // Trying to paste original type as generic parameter suffix = CorrectGenericSuffix(associateTypeName, 1); - result = Activate(location.First, suffix, new[] {originalForType}, constructorParams) as T; + result = Activate(location.First, suffix, new[] { originalForType }, constructorParams) as T; if (result != null) { foundForType = currentForType; return result; @@ -319,7 +336,7 @@ private static T CreateAssociateInternal(Type originalForType, // Trying a generic one (e.g. EnumerableInterfaceHandler`2) Type[] newGenericArguments; if (genericArguments == null || genericArguments.Length == 0) { - newGenericArguments = new[] {originalForType}; + newGenericArguments = new[] { originalForType }; associateTypeName = AddSuffix($"{location.Second}.{associateTypePrefix}`1", associateTypeSuffix); } else { @@ -482,7 +499,7 @@ public static string AddSuffix(string typeName, string suffix) /// /// Assembly where the type is located. /// Name of the type to instantiate. - /// Generic arguments for the type to instantiate + /// Generic arguments for the type to instantiate /// ( means type isn't a generic type definition). /// Arguments to pass to the type constructor. /// An instance of specified type; , if either no such a type, @@ -501,7 +518,7 @@ public static object Activate(Assembly assembly, string typeName, Type[] generic /// or an error has occurred. /// /// Generic type definition to instantiate. - /// Generic arguments for the type to instantiate + /// Generic arguments for the type to instantiate /// ( means isn't a generic type definition). /// Arguments to pass to the type constructor. /// An instance of specified type; , if either no such a type, @@ -592,7 +609,7 @@ public static object Activate(this Type type, Type[] genericArguments, params ob } /// - /// Gets the public constructor of type + /// Gets the public constructor of type /// accepting specified . /// /// The type to get the constructor for. @@ -601,29 +618,34 @@ public static object Activate(this Type type, Type[] genericArguments, params ob /// Appropriate constructor, if a single match is found; /// otherwise, . /// - public static ConstructorInfo GetConstructor(this Type type, object[] arguments) - { + public static ConstructorInfo GetConstructor(this Type type, object[] arguments) => + GetSingleConstructor(type, arguments.Select(a => a?.GetType()).ToArray()); + + public static ConstructorInfo GetSingleConstructor(this Type type, Type[] argumentTypes) => + constructorInfoByTypes.GetOrAdd((type, argumentTypes), ConstructorExtractor); + + private static readonly Func<(Type, Type[]), ConstructorInfo> ConstructorExtractor = t => { + (var type, var argumentTypes) = t; var constructors = from ctor in type.GetConstructors() let parameters = ctor.GetParameters() - where parameters.Length == arguments.Length - let zipped = parameters.Zip(arguments, (parameter, argument) => (parameter, argument)) + where parameters.Length == argumentTypes.Length + let zipped = parameters.Zip(argumentTypes, (parameter, argumentType) => (parameter, argumentType)) where ( from pair in zipped let parameter = pair.parameter let parameterType = parameter.ParameterType - let argument = pair.argument - let argumentType = argument == null ? WellKnownTypes.Object : argument.GetType() + let argumentType = pair.argumentType select !parameter.IsOut && ( - parameterType.IsAssignableFrom(argumentType) || - (!parameterType.IsValueType && argument == null) || - (parameterType.IsNullable() && argument == null) + parameterType.IsAssignableFrom(argumentType ?? WellKnownTypes.Object) || + (!parameterType.IsValueType && argumentType == null) || + (parameterType.IsNullable() && argumentType == null) ) ).All(passed => passed) select ctor; return constructors.SingleOrDefault(); - } + }; /// /// Orders the specified by their inheritance @@ -880,7 +902,7 @@ public static bool IsNullable(this Type type) => public static bool IsFinal() => IsFinal(typeof(T)); /// - /// Gets the delegate "Invoke" method (describing the delegate) for + /// Gets the delegate "Invoke" method (describing the delegate) for /// the specified . /// /// Type of the delegate to get the "Invoke" method of. @@ -998,7 +1020,7 @@ public static Type GetGenericInterface(this Type type, Type openGenericInterface /// /// If is a reference type or a instance /// returns . - /// Otherwise returns of . + /// Otherwise returns of . /// public static Type ToNullable(this Type type) {