diff --git a/Directory.Build.props b/Directory.Build.props
index e1e2bf5fbb..3028fe456b 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -132,5 +132,6 @@
$(DefineConstants);DO_DATEONLY
+ $(DefineConstants);DO_SAFE_COLLECTION_WRAPPER
diff --git a/Orm/Xtensive.Orm.Tests.Core/Helpers/TopologicalSorterTest.cs b/Orm/Xtensive.Orm.Tests.Core/Helpers/TopologicalSorterTest.cs
index 510fa970e8..ff3189c2a8 100644
--- a/Orm/Xtensive.Orm.Tests.Core/Helpers/TopologicalSorterTest.cs
+++ b/Orm/Xtensive.Orm.Tests.Core/Helpers/TopologicalSorterTest.cs
@@ -63,7 +63,7 @@ private static void InternalPerformanceTest(int nodeCount, int averageConnection
List> removedEdges;
var result = TopologicalSorter.Sort(nodes, out removedEdges);
if (!allowLoops)
- Assert.AreEqual(nodeCount, result.Count);
+ Assert.AreEqual(nodeCount, result.Count());
}
GC.GetTotalMemory(true);
}
@@ -132,7 +132,7 @@ public void CombinedTest()
private void TestSort(T[] data, Predicate connector, T[] expected, T[] loops)
{
List> actualLoopNodes;
- List actual = TopologicalSorter.Sort(data, connector, out actualLoopNodes);
+ List actual = TopologicalSorter.Sort(data, connector, out actualLoopNodes).ToList();
T[] actualLoops = null;
if (actualLoopNodes != null)
actualLoops = actualLoopNodes
diff --git a/Orm/Xtensive.Orm/Core/Extensions/ListExtensions.cs b/Orm/Xtensive.Orm/Core/Extensions/ListExtensions.cs
index d50fdcb846..3c72faf921 100644
--- a/Orm/Xtensive.Orm/Core/Extensions/ListExtensions.cs
+++ b/Orm/Xtensive.Orm/Core/Extensions/ListExtensions.cs
@@ -8,7 +8,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
-
+using System.Runtime.CompilerServices;
namespace Xtensive.Core
{
@@ -119,5 +119,29 @@ public static void EnsureIndexIsValid(this IList list, int index)
if (index < 0 || index >= list.Count)
throw new IndexOutOfRangeException(Strings.ExIndexOutOfRange);
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static IReadOnlyList AsSafeWrapper(this List list) =>
+#if DO_SAFE_COLLECTION_WRAPPER
+ list.AsReadOnly();
+#else
+ list;
+#endif
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static IReadOnlyList AsSafeWrapper(this IReadOnlyList list) =>
+#if DO_SAFE_COLLECTION_WRAPPER
+ new ReadOnlyCollection(list);
+#else
+ list;
+#endif
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static IReadOnlyList AsSafeWrapper(this T[] array) =>
+#if DO_SAFE_COLLECTION_WRAPPER
+ Array.AsReadOnly(array);
+#else
+ array;
+#endif
}
}
\ No newline at end of file
diff --git a/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs b/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs
index 2262333a8b..6412d3e43d 100644
--- a/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs
+++ b/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs
@@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
+using Xtensive.Core;
namespace Xtensive.Linq
{
@@ -17,7 +18,7 @@ namespace Xtensive.Linq
///
public abstract class ExpressionVisitor : ExpressionVisitor
{
- protected override ReadOnlyCollection VisitExpressionList(ReadOnlyCollection expressions)
+ protected override IReadOnlyList VisitExpressionList(ReadOnlyCollection expressions)
{
bool isChanged = false;
var results = new List(expressions.Count);
@@ -27,7 +28,7 @@ protected override ReadOnlyCollection VisitExpressionList(ReadOnlyCo
results.Add(p);
isChanged |= !ReferenceEquals(expression, p);
}
- return isChanged ? results.AsReadOnly() : expressions;
+ return isChanged ? results.AsSafeWrapper() : expressions;
}
///
@@ -37,8 +38,8 @@ protected override ReadOnlyCollection VisitExpressionList(ReadOnlyCo
/// Visit result.
protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
{
- ReadOnlyCollection arguments = VisitExpressionList(initializer.Arguments);
- if (arguments!=initializer.Arguments) {
+ var arguments = VisitExpressionList(initializer.Arguments);
+ if (arguments != initializer.Arguments) {
return Expression.ElementInit(initializer.AddMethod, arguments);
}
return initializer;
@@ -49,7 +50,7 @@ protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
///
/// The original element initializer list.
/// Visit result.
- protected virtual ReadOnlyCollection VisitElementInitializerList(ReadOnlyCollection original)
+ protected virtual IReadOnlyList VisitElementInitializerList(ReadOnlyCollection original)
{
var results = new List();
bool isChanged = false;
@@ -59,7 +60,7 @@ protected virtual ReadOnlyCollection VisitElementInitializerList(Re
results.Add(p);
isChanged |= !ReferenceEquals(originalIntializer, p);
}
- return isChanged ? results.AsReadOnly() : original;
+ return isChanged ? results.AsSafeWrapper() : original;
}
///
@@ -246,7 +247,7 @@ protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBindi
///
/// The original binding list.
/// Visit result.
- protected virtual ReadOnlyCollection VisitBindingList(ReadOnlyCollection original)
+ protected virtual IReadOnlyList VisitBindingList(ReadOnlyCollection original)
{
var results = new List();
bool isChanged = false;
@@ -256,7 +257,7 @@ protected virtual ReadOnlyCollection VisitBindingList(ReadOnlyCol
results.Add(p);
isChanged |= !ReferenceEquals(originalBinding, p);
}
- return isChanged ? results.AsReadOnly() : original;
+ return isChanged ? results.AsSafeWrapper() : original;
}
protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
diff --git a/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs b/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs
index 54ddfc3726..4c50e3a985 100644
--- a/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs
+++ b/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs
@@ -9,6 +9,7 @@
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using Xtensive.Reflection;
+using Xtensive.Core;
@@ -139,14 +140,14 @@ protected virtual TResult Visit(Expression e)
///
/// The expression list.
/// Visit result.
- protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection expressions)
+ protected virtual IReadOnlyList VisitExpressionList(ReadOnlyCollection expressions)
{
var results = new List(expressions.Count);
for (int i = 0, n = expressions.Count; i < n; i++) {
var p = Visit(expressions[i]);
results.Add(p);
}
- return results.AsReadOnly();
+ return results.AsSafeWrapper();
}
///
diff --git a/Orm/Xtensive.Orm/Orm/Building/Builders/AssociationBuilder.cs b/Orm/Xtensive.Orm/Orm/Building/Builders/AssociationBuilder.cs
index db882628e5..e08a5538a0 100644
--- a/Orm/Xtensive.Orm/Orm/Building/Builders/AssociationBuilder.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/Builders/AssociationBuilder.cs
@@ -25,7 +25,7 @@ public static void BuildAssociation(BuildingContext context, FieldDef fieldDef,
fieldDef.OnOwnerRemove, fieldDef.OnTargetRemove);
association.Name = context.NameBuilder.BuildAssociationName(association);
context.Model.Associations.Add(association);
- field.Associations.Add(association);
+ field.AddAssociation(association);
if (!fieldDef.PairTo.IsNullOrEmpty())
context.PairedAssociations.Add(new Pair(association, fieldDef.PairTo));
@@ -40,8 +40,8 @@ public static void BuildAssociation(BuildingContext context, AssociationInfo ori
.Where(a => a.TargetType == association.TargetType)
.ToList();
foreach (var toRemove in associationsToRemove)
- field.Associations.Remove(toRemove);
- field.Associations.Add(association);
+ field.RemoveAssociation(toRemove);
+ field.AddAssociation(association);
var pairTo = context.PairedAssociations.Where(p => p.First==origin).FirstOrDefault();
if (pairTo.First!=null)
@@ -86,9 +86,9 @@ public static void BuildReversedAssociation(BuildingContext context, Association
.Where(a => a.TargetType == association.TargetType)
.ToList();
foreach (var toRemove in associationsToRemove)
- field.Associations.Remove(toRemove);
+ field.RemoveAssociation(toRemove);
- field.Associations.Add(association);
+ field.AddAssociation(association);
}
}
diff --git a/Orm/Xtensive.Orm/Orm/Building/Builders/IndexBuilder.cs b/Orm/Xtensive.Orm/Orm/Building/Builders/IndexBuilder.cs
index 8ec6e63efc..a37cd78371 100644
--- a/Orm/Xtensive.Orm/Orm/Building/Builders/IndexBuilder.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/Builders/IndexBuilder.cs
@@ -533,7 +533,7 @@ private IndexInfo BuildFilterIndex(TypeInfo reflectedType, IndexInfo indexToFilt
& (IndexAttributes.Primary | IndexAttributes.Secondary | IndexAttributes.Unique | IndexAttributes.Abstract)
| IndexAttributes.Filtered | IndexAttributes.Virtual;
var result = new IndexInfo(reflectedType, attributes, indexToFilter, Array.Empty()) {
- FilterByTypes = filterByTypes.ToList().AsReadOnly()
+ FilterByTypes = filterByTypes.ToList().AsSafeWrapper()
};
// Adding key columns
@@ -760,7 +760,7 @@ private IndexInfo BuildViewIndex(TypeInfo reflectedType, IndexInfo indexToApplyV
}
result.ValueColumns.AddRange(valueColumns);
- result.SelectColumns = columnMap.AsReadOnly();
+ result.SelectColumns = columnMap.AsSafeWrapper();
result.Name = nameBuilder.BuildIndexName(reflectedType, result);
result.Group = BuildColumnGroup(result);
diff --git a/Orm/Xtensive.Orm/Orm/Building/Builders/ModelBuilder.cs b/Orm/Xtensive.Orm/Orm/Building/Builders/ModelBuilder.cs
index be674702f7..3e1ef0c2c7 100644
--- a/Orm/Xtensive.Orm/Orm/Building/Builders/ModelBuilder.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/Builders/ModelBuilder.cs
@@ -277,7 +277,7 @@ private void PreprocessAssociations()
foreach (var association in associationsToRemove) {
context.Model.Associations.Remove(association);
- refField.Associations.Remove(association);
+ refField.RemoveAssociation(association);
}
foreach (var association in associationsToKeep) {
var interfaceAssociationsToRemove = interfaceAssociations
@@ -287,10 +287,10 @@ private void PreprocessAssociations()
foreach (var interfaceAssociation in interfaceAssociationsToRemove)
interfaceAssociations.Remove(interfaceAssociation);
}
- refField.Associations.AddRange(interfaceAssociations);
+ refField.AddAssociations(interfaceAssociations);
foreach (var association in inheritedAssociations) {
- if (!refField.Associations.Contains(association.Name))
- refField.Associations.Add(association);
+ if (!refField.ContainsAssociation(association.Name))
+ refField.AddAssociation(association);
if (!context.Model.Associations.Contains(association))
context.Model.Associations.Add(association);
}
diff --git a/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs b/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs
index 299bf7c8fe..1a27bc1470 100644
--- a/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs
@@ -39,6 +39,11 @@ public TypeInfo BuildType(TypeDef typeDef)
{
using (BuildLog.InfoRegion(nameof(Strings.LogBuildingX), typeDef.UnderlyingType.GetShortName())) {
+ var validators = typeDef.Validators;
+ if (typeDef.IsEntity && DeclaresOnValidate(typeDef.UnderlyingType)) {
+ validators.Add(new EntityValidator());
+ }
+
var typeInfo = new TypeInfo(context.Model, typeDef.Attributes) {
UnderlyingType = typeDef.UnderlyingType,
Name = typeDef.Name,
@@ -46,13 +51,9 @@ public TypeInfo BuildType(TypeDef typeDef)
MappingDatabase = typeDef.MappingDatabase,
MappingSchema = typeDef.MappingSchema,
HasVersionRoots = typeDef.UnderlyingType.GetInterfaces().Any(type => type == typeof(IHasVersionRoots)),
- Validators = typeDef.Validators,
+ Validators = validators,
};
- if (typeInfo.IsEntity && DeclaresOnValidate(typeInfo.UnderlyingType)) {
- typeInfo.Validators.Add(new EntityValidator());
- }
-
if (typeDef.StaticTypeId != null) {
typeInfo.TypeId = typeDef.StaticTypeId.Value;
}
@@ -232,6 +233,16 @@ private FieldInfo BuildDeclaredField(TypeInfo type, FieldDef fieldDef)
{
BuildLog.Info(nameof(Strings.LogBuildingDeclaredFieldXY), type.Name, fieldDef.Name);
+ var validators = fieldDef.Validators;
+
+ if (fieldDef.IsStructure && DeclaresOnValidate(fieldDef.ValueType)) {
+ validators.Add(new StructureFieldValidator());
+ }
+
+ if (fieldDef.IsEntitySet && DeclaresOnValidate(fieldDef.ValueType)) {
+ validators.Add(new EntitySetFieldValidator());
+ }
+
var fieldInfo = new FieldInfo(type, fieldDef.Attributes) {
UnderlyingProperty = fieldDef.UnderlyingProperty,
Name = fieldDef.Name,
@@ -242,17 +253,9 @@ private FieldInfo BuildDeclaredField(TypeInfo type, FieldDef fieldDef)
Length = fieldDef.Length,
Scale = fieldDef.Scale,
Precision = fieldDef.Precision,
- Validators = fieldDef.Validators,
+ Validators = validators,
};
- if (fieldInfo.IsStructure && DeclaresOnValidate(fieldInfo.ValueType)) {
- fieldInfo.Validators.Add(new StructureFieldValidator());
- }
-
- if (fieldInfo.IsEntitySet && DeclaresOnValidate(fieldInfo.ValueType)) {
- fieldInfo.Validators.Add(new EntitySetFieldValidator());
- }
-
type.Fields.Add(fieldInfo);
if (fieldInfo.IsEntitySet) {
diff --git a/Orm/Xtensive.Orm/Orm/Building/BuildingContext.cs b/Orm/Xtensive.Orm/Orm/Building/BuildingContext.cs
index 7921126610..5b8fd3ab88 100644
--- a/Orm/Xtensive.Orm/Orm/Building/BuildingContext.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/BuildingContext.cs
@@ -62,12 +62,12 @@ public sealed class BuildingContext
///
/// Gets all available implementations.
///
- public ICollection Modules { get; private set; }
+ public IReadOnlyList Modules { get; }
///
/// Gets all available implementations.
///
- public ICollection Modules2 { get; private set; }
+ public IReadOnlyList Modules2 { get; }
internal ModelDefBuilder ModelDefBuilder { get; set; }
@@ -85,8 +85,8 @@ internal BuildingContext(DomainBuilderConfiguration builderConfiguration)
ModelInspectionResult = new ModelInspectionResult();
DependencyGraph = new Graph();
- Modules = BuilderConfiguration.Services.Modules.ToList().AsReadOnly();
- Modules2 = Modules.OfType().ToList().AsReadOnly();
+ Modules = BuilderConfiguration.Services.Modules.AsSafeWrapper();
+ Modules2 = Modules.OfType().ToList().AsSafeWrapper();
Validator = new Validator(builderConfiguration.Services.ProviderInfo.SupportedTypes);
DefaultSchemaInfo = builderConfiguration.DefaultSchemaInfo;
}
diff --git a/Orm/Xtensive.Orm/Orm/Building/Definitions/FieldDef.cs b/Orm/Xtensive.Orm/Orm/Building/Definitions/FieldDef.cs
index 7c5418e1c7..9ada902b7d 100644
--- a/Orm/Xtensive.Orm/Orm/Building/Definitions/FieldDef.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/Definitions/FieldDef.cs
@@ -287,7 +287,7 @@ public string PairTo
///
/// Gets of instances associated with this field.
///
- public IList Validators { get; private set; }
+ public List Validators { get; } = new();
internal bool IsDeclaredAsNullable
{
@@ -325,7 +325,6 @@ internal FieldDef(Type valueType, Validator validator)
if ((valueType.IsClass || valueType.IsInterface) && !IsStructure)
attributes |= FieldAttributes.Nullable;
ValueType = valueType;
- Validators = new List();
// Nullable
if (valueType.IsNullable()) {
diff --git a/Orm/Xtensive.Orm/Orm/Building/Definitions/TypeDef.cs b/Orm/Xtensive.Orm/Orm/Building/Definitions/TypeDef.cs
index 1e8af2638f..75bf6323ad 100644
--- a/Orm/Xtensive.Orm/Orm/Building/Definitions/TypeDef.cs
+++ b/Orm/Xtensive.Orm/Orm/Building/Definitions/TypeDef.cs
@@ -119,7 +119,7 @@ public NodeCollection Implementors
///
/// Gets instances associated with this type.
///
- public IList Validators { get; private set; }
+ public List Validators { get; } = new();
///
/// Gets or sets the type discriminator value.
@@ -225,8 +225,6 @@ internal TypeDef(ModelDefBuilder builder, Type type, Validator validator)
implementors = IsInterface
? new NodeCollection(this, "Implementors")
: NodeCollection.Empty;
-
- Validators = new List();
}
}
}
\ No newline at end of file
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/IHasNestedNodes.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/IHasNestedNodes.cs
index 50d1354035..283995835e 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/IHasNestedNodes.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/IHasNestedNodes.cs
@@ -11,10 +11,10 @@ namespace Xtensive.Orm.Internals.Prefetch
{
internal interface IHasNestedNodes
{
- ReadOnlyCollection NestedNodes { get; }
+ IReadOnlyList NestedNodes { get; }
IReadOnlyCollection ExtractKeys(object target);
- IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection nestedNodes);
+ IHasNestedNodes ReplaceNestedNodes(IReadOnlyList nestedNodes);
}
}
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/KeyExtractorNode.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/KeyExtractorNode.cs
index 9b3af6a0e6..9eb36884c4 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/KeyExtractorNode.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/KeyExtractorNode.cs
@@ -15,7 +15,7 @@ internal class KeyExtractorNode : Node, IHasNestedNodes
{
public Func> KeyExtractor { get; }
- public ReadOnlyCollection NestedNodes { get; }
+ public IReadOnlyList NestedNodes { get; }
IReadOnlyCollection IHasNestedNodes.ExtractKeys(object target)
{
@@ -27,10 +27,8 @@ public IReadOnlyCollection ExtractKeys(T target)
return KeyExtractor.Invoke(target);
}
- public IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection nestedNodes)
- {
- return new KeyExtractorNode(KeyExtractor, nestedNodes);
- }
+ public IHasNestedNodes ReplaceNestedNodes(IReadOnlyList nestedNodes) =>
+ new KeyExtractorNode(KeyExtractor, nestedNodes);
public override Node Accept(NodeVisitor visitor)
{
@@ -42,7 +40,7 @@ protected override string GetDescription()
return $"KeyExtraction<{typeof(T).Name}>";
}
- public KeyExtractorNode(Func> extractor, ReadOnlyCollection nestedNodes)
+ public KeyExtractorNode(Func> extractor, IReadOnlyList nestedNodes)
: base("*")
{
ArgumentValidator.EnsureArgumentNotNull(extractor, nameof(extractor));
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeAggregator.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeAggregator.cs
index d239cce2a7..f5a7c1efbd 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeAggregator.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeAggregator.cs
@@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
+using Xtensive.Core;
namespace Xtensive.Orm.Internals.Prefetch
{
@@ -26,7 +27,7 @@ public static IList> Aggregate(IEnumerable VisitNodeList(ReadOnlyCollection nodes)
+ public override IReadOnlyList VisitNodeList(IReadOnlyList nodes)
{
var result = new List();
foreach (var group in nodes.Where(n => n!=null).GroupBy(n => n.Path)) {
@@ -36,11 +37,11 @@ public override ReadOnlyCollection VisitNodeList(ReadOnlyCollecti
result.Add(node);
else {
var nodeToVisit = (BaseFieldNode) container.ReplaceNestedNodes(
- new ReadOnlyCollection(group.Cast().SelectMany(c => c.NestedNodes).ToList()));
+ group.Cast().SelectMany(c => c.NestedNodes).ToList().AsSafeWrapper());
result.Add((BaseFieldNode) Visit(nodeToVisit));
}
}
- return new ReadOnlyCollection(result);
+ return result.AsSafeWrapper();
}
// Constructor
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeBuilder.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeBuilder.cs
index ebc5ad3fad..d0321d4432 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeBuilder.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeBuilder.cs
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2020 Xtensive LLC.
+// Copyright (C) 2012-2020 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Denis Krjuchkov
@@ -119,9 +119,9 @@ private IEnumerable VisitMemberAccess(MemberExpression access)
return EnumerableUtils.One(result);
}
- private static ObjectModel.ReadOnlyCollection WrapNodes(IEnumerable nodes)
+ private static IReadOnlyList WrapNodes(IEnumerable nodes)
{
- return nodes.ToList().AsReadOnly();
+ return nodes.ToList().AsSafeWrapper();
}
private IEnumerable VisitChildren(Expression expression)
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeVisitor.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeVisitor.cs
index ce371ec875..ec98bc9a94 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeVisitor.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeVisitor.cs
@@ -4,7 +4,9 @@
// Created by: Alexis Kochetov
// Created: 2011.01.14
+using System.Collections.Generic;
using System.Collections.ObjectModel;
+using Xtensive.Core;
namespace Xtensive.Orm.Internals.Prefetch
{
@@ -17,7 +19,7 @@ public virtual Node Visit(Node node)
return node.Accept(this);
}
- public virtual ReadOnlyCollection VisitNodeList(ReadOnlyCollection nodes)
+ public virtual IReadOnlyList VisitNodeList(IReadOnlyList nodes)
{
BaseFieldNode[] list = null;
var index = 0;
@@ -35,9 +37,7 @@ public virtual ReadOnlyCollection VisitNodeList(ReadOnlyCollectio
}
index++;
}
- return list==null
- ? nodes
- : new ReadOnlyCollection(list);
+ return list?.AsSafeWrapper() ?? nodes;
}
public virtual Node VisitKeyExtractorNode(KeyExtractorNode keyExtractorNode)
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/ReferenceNode.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/ReferenceNode.cs
index 5bceb8dc84..13577e3796 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/ReferenceNode.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/ReferenceNode.cs
@@ -15,7 +15,7 @@ internal sealed class ReferenceNode : BaseFieldNode, IHasNestedNodes
{
public TypeInfo ReferenceType { get; private set; }
- public ReadOnlyCollection NestedNodes { get; private set; }
+ public IReadOnlyList NestedNodes { get; private set; }
public IReadOnlyCollection ExtractKeys(object target)
{
@@ -30,10 +30,8 @@ public IReadOnlyCollection ExtractKeys(object target)
: new[] {referenceKey};
}
- public IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection nestedNodes)
- {
- return new ReferenceNode(Path, Field, ReferenceType, NestedNodes);
- }
+ public IHasNestedNodes ReplaceNestedNodes(IReadOnlyList nestedNodes) =>
+ new ReferenceNode(Path, Field, ReferenceType, NestedNodes);
public override Node Accept(NodeVisitor visitor)
{
@@ -42,7 +40,7 @@ public override Node Accept(NodeVisitor visitor)
// Constructors
- public ReferenceNode(string path, FieldInfo field, TypeInfo referenceType, ReadOnlyCollection nestedNodes)
+ public ReferenceNode(string path, FieldInfo field, TypeInfo referenceType, IReadOnlyList nestedNodes)
: base(path, field)
{
ReferenceType = referenceType;
diff --git a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/SetNode.cs b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/SetNode.cs
index 5650ef97a9..8d00ff0ac4 100644
--- a/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/SetNode.cs
+++ b/Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/SetNode.cs
@@ -14,7 +14,7 @@ namespace Xtensive.Orm.Internals.Prefetch
{
internal class SetNode : BaseFieldNode, IHasNestedNodes
{
- public ReadOnlyCollection NestedNodes { get; }
+ public IReadOnlyList NestedNodes { get; }
public TypeInfo ElementType { get; }
@@ -30,7 +30,7 @@ public IReadOnlyCollection ExtractKeys(object target)
return fetchedKeys.ToArray(fetchedKeys.Count);
}
- public IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection nestedNodes) =>
+ public IHasNestedNodes ReplaceNestedNodes(IReadOnlyList nestedNodes) =>
new SetNode(Path, Field, ElementType, NestedNodes);
public override Node Accept(NodeVisitor visitor) => visitor.VisitSetNode(this);
@@ -38,7 +38,7 @@ public IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection nest
// Constructors
- public SetNode(string path, FieldInfo field, TypeInfo elementType, ReadOnlyCollection nestedNodes)
+ public SetNode(string path, FieldInfo field, TypeInfo elementType, IReadOnlyList nestedNodes)
: base(path, field)
{
ElementType = elementType;
diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs
index ba291e6e7f..aa9b205e6e 100644
--- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs
+++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs
@@ -90,9 +90,8 @@ private static ProjectionExpression Optimize(ProjectionExpression origin)
if (usedColumns.Count == 0)
usedColumns.Add(0);
if (usedColumns.Count < origin.ItemProjector.DataSource.Header.Length) {
- var usedColumnsArray = usedColumns.ToArray();
- var resultProvider = new SelectProvider(originProvider, usedColumnsArray);
- var itemProjector = origin.ItemProjector.Remap(resultProvider, usedColumnsArray);
+ var resultProvider = new SelectProvider(originProvider, usedColumns);
+ var itemProjector = origin.ItemProjector.Remap(resultProvider, usedColumns);
var result = origin.Apply(itemProjector);
return result;
}
diff --git a/Orm/Xtensive.Orm/Orm/Model/ColumnIndexMap.cs b/Orm/Xtensive.Orm/Orm/Model/ColumnIndexMap.cs
index eeab313606..d2f14453ae 100644
--- a/Orm/Xtensive.Orm/Orm/Model/ColumnIndexMap.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/ColumnIndexMap.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
+using Xtensive.Core;
namespace Xtensive.Orm.Model
@@ -14,22 +15,22 @@ namespace Xtensive.Orm.Model
/// A map of useful column indexes.
///
[Serializable]
- public sealed class ColumnIndexMap
+ public readonly struct ColumnIndexMap
{
///
/// Gets or sets positions of system columns within .
///
- public IList System { get; private set; }
+ public IReadOnlyList System { get; }
///
/// Gets or sets positions of lazy load columns within .
///
- public IList LazyLoad { get; private set; }
+ public IReadOnlyList LazyLoad { get; }
///
/// Gets or sets positions of regular columns (not system and not lazy load) within .
///
- public IList Regular { get; private set; }
+ public IReadOnlyList Regular { get; }
// Constructors
@@ -40,11 +41,11 @@ public sealed class ColumnIndexMap
/// The system columns.
/// The regular columns.
/// The lazy load columns.
- public ColumnIndexMap(List system, List regular, List lazyLoad)
+ public ColumnIndexMap(IReadOnlyList system, IReadOnlyList regular, IReadOnlyList lazyLoad)
{
- System = system.AsReadOnly();
- LazyLoad = lazyLoad.AsReadOnly();
- Regular = regular.AsReadOnly();
+ System = system.AsSafeWrapper();
+ LazyLoad = lazyLoad.AsSafeWrapper();
+ Regular = regular.AsSafeWrapper();
}
}
-}
\ No newline at end of file
+}
diff --git a/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs b/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs
index b15369e0e1..a1371b8302 100644
--- a/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/FieldInfo.cs
@@ -60,7 +60,6 @@ public sealed class FieldInfo : MappedNode,
private int fieldId;
private int? cachedHashCode;
- private IList validators;
private Segment mappingInfo;
#region IsXxx properties
@@ -545,11 +544,12 @@ public ColumnInfo Column
///
public AssociationInfo GetAssociation(TypeInfo targetType)
{
- if (associations.Count == 0)
- return null;
-
- if (associations.Count == 1)
- return associations[0];
+ switch (Associations.Count) {
+ case 0:
+ return null;
+ case 1:
+ return associations[0];
+ }
var ordered = IsLocked
? associations
@@ -559,11 +559,26 @@ public AssociationInfo GetAssociation(TypeInfo targetType)
a => a.TargetType.UnderlyingType.IsAssignableFrom(targetType.UnderlyingType));
}
- public NodeCollection Associations
+ public IReadOnlyList Associations => (IReadOnlyList)associations ?? Array.Empty();
+
+ public bool ContainsAssociation(string associationName) => associations?.Contains(associationName) == true;
+
+ public void AddAssociation(AssociationInfo association) =>
+ EnsureAssociations().Add(association);
+
+ public void AddAssociations(IReadOnlyList range)
{
- get { return associations; }
+ if (range.Count > 0) {
+ EnsureAssociations().AddRange(range);
+ }
}
+ public void RemoveAssociation(AssociationInfo association) =>
+ _ = EnsureAssociations().Remove(association);
+
+ private NodeCollection EnsureAssociations() =>
+ associations ??= new NodeCollection(this, "Associations");
+
///
/// Gets or sets field's adapter index.
///
@@ -582,14 +597,7 @@ public int AdapterIndex
/// Gets instances
/// associated with this field.
///
- public IList Validators
- {
- get { return validators; }
- internal set {
- EnsureNotLocked();
- validators = value;
- }
- }
+ public IReadOnlyList Validators { get; init; }
///
/// Gets value indicating if this field
@@ -658,7 +666,7 @@ public override void UpdateState()
columns?.Clear(); // To prevent event handler leak
columns = null;
- HasImmediateValidators = validators.Count > 0 && validators.Any(v => v.IsImmediate);
+ HasImmediateValidators = Validators.Count > 0 && Validators.Any(v => v.IsImmediate);
CreateMappingInfo();
}
@@ -669,16 +677,15 @@ public override void Lock(bool recursive)
base.Lock(recursive);
if (!recursive)
return;
- validators = Array.AsReadOnly(validators.ToArray());
Fields.Lock(true);
if (column != null)
column.Lock(true);
- if (associations.Count > 1) {
+ if (Associations.Count > 1) {
var sorted = associations.Reorder();
associations = new NodeCollection(associations.Owner, associations.Name);
associations.AddRange(sorted);
}
- associations.Lock(false);
+ associations?.Lock(false);
}
private void CreateMappingInfo()
@@ -778,9 +785,9 @@ public FieldInfo Clone()
defaultValue = defaultValue,
defaultSqlExpression = defaultSqlExpression,
DeclaringField = DeclaringField,
- Validators = Validators.Select(v => v.CreateNew()).ToList(),
+ Validators = Validators.Select(v => v.CreateNew()).ToArray(),
};
- clone.Associations.AddRange(associations);
+ clone.AddAssociations(Associations);
return clone;
}
@@ -808,7 +815,6 @@ private FieldInfo(TypeInfo declaringType, TypeInfo reflectedType, FieldAttribute
Fields = IsEntity || IsStructure
? new FieldInfoCollection(this, "Fields")
: FieldInfoCollection.Empty;
- associations = new NodeCollection(this, "Associations");
}
}
-}
\ No newline at end of file
+}
diff --git a/Orm/Xtensive.Orm/Orm/Model/HierarchyInfo.cs b/Orm/Xtensive.Orm/Orm/Model/HierarchyInfo.cs
index a2686c6f49..ffb293a0d3 100644
--- a/Orm/Xtensive.Orm/Orm/Model/HierarchyInfo.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/HierarchyInfo.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
+using Xtensive.Core;
namespace Xtensive.Orm.Model
{
@@ -47,7 +48,7 @@ public override void UpdateState()
Key.UpdateState();
var list = new List {Root};
list.AddRange(Root.RecursiveDescendants);
- Types = list.AsReadOnly();
+ Types = list.AsSafeWrapper();
if (Types.Count == 1)
InheritanceSchema = InheritanceSchema.ConcreteTable;
if (TypeDiscriminatorMap != null)
diff --git a/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs b/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs
index 5156889784..1a5785c949 100644
--- a/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs
@@ -35,11 +35,11 @@ public sealed class IndexInfo : MappedNode
private readonly IndexInfo declaringIndex;
private double fillFactor;
private string shortName;
- private ReadOnlyCollection columns;
+ private IReadOnlyList columns;
private TupleDescriptor tupleDescriptor;
private TupleDescriptor keyTupleDescriptor;
- private IList filterByTypes;
- private IList selectColumns;
+ private IReadOnlyList filterByTypes;
+ private IReadOnlyList selectColumns;
private List>> valueColumnsMap;
private LambdaExpression filterExpression;
private PartialIndexFilterInfo filter;
@@ -173,7 +173,7 @@ public IndexInfo DeclaringIndex
///
/// Gets the types for index.
///
- public IList FilterByTypes
+ public IReadOnlyList FilterByTypes
{
get { return filterByTypes; }
set
@@ -214,7 +214,7 @@ public PartialIndexFilterInfo Filter {
///
/// Gets the column indexes for index.
///
- public IList SelectColumns
+ public IReadOnlyList SelectColumns
{
get { return selectColumns; }
set
@@ -339,7 +339,7 @@ public override void UpdateState()
var lazy = new List();
var regular = new List();
- for (int i = 0; i < columns.Count; i++) {
+ for (int i = 0, count = columns.Count; i < count; i++) {
var item = columns[i];
if (item.IsPrimaryKey || item.IsSystem)
system.Add(i);
@@ -392,7 +392,7 @@ private void CreateColumns()
{
var result = new List(keyColumns.Select(pair => pair.Key));
result.AddRange(valueColumns);
- columns = result.AsReadOnly();
+ columns = result.AsSafeWrapper();
}
diff --git a/Orm/Xtensive.Orm/Orm/Model/PartialIndexFilterInfo.cs b/Orm/Xtensive.Orm/Orm/Model/PartialIndexFilterInfo.cs
index 2363000d84..b37d3f18d9 100644
--- a/Orm/Xtensive.Orm/Orm/Model/PartialIndexFilterInfo.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/PartialIndexFilterInfo.cs
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 Xtensive LLC.
+// Copyright (C) 2011 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Created by: Denis Krjuchkov
@@ -32,12 +32,12 @@ public LambdaExpression Expression
}
}
- private IList fields;
+ private IReadOnlyList fields;
///
/// Fields used in .
///
- public IList Fields
+ public IReadOnlyList Fields
{
get { return fields; }
set
@@ -56,7 +56,6 @@ public override void Lock(bool recursive)
throw Exceptions.NotInitialized("Expression");
if (Fields==null)
throw Exceptions.NotInitialized("Fields");
- fields = fields.ToList().AsReadOnly();
base.Lock(recursive);
}
}
diff --git a/Orm/Xtensive.Orm/Orm/Model/TypeIndexInfoCollection.cs b/Orm/Xtensive.Orm/Orm/Model/TypeIndexInfoCollection.cs
index ca2270fc6d..a166ed7e17 100644
--- a/Orm/Xtensive.Orm/Orm/Model/TypeIndexInfoCollection.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/TypeIndexInfoCollection.cs
@@ -8,6 +8,7 @@
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
+using Xtensive.Core;
namespace Xtensive.Orm.Model
{
@@ -39,7 +40,7 @@ public IReadOnlyList RealPrimaryIndexes
get {
return IsLocked
? realPrimaryIndexes
- : FindRealPrimaryIndexes(PrimaryIndex).AsReadOnly();
+ : FindRealPrimaryIndexes(PrimaryIndex).AsSafeWrapper();
}
}
@@ -84,8 +85,8 @@ public override void UpdateState()
{
base.UpdateState();
primaryIndex = FindPrimaryIndex();
- realPrimaryIndexes = FindRealPrimaryIndexes(primaryIndex).AsReadOnly();
- indexesContainingAllData = FindIndexesContainingAllData().AsReadOnly();
+ realPrimaryIndexes = FindRealPrimaryIndexes(primaryIndex).AsSafeWrapper();
+ indexesContainingAllData = FindIndexesContainingAllData().AsSafeWrapper();
}
private IndexInfo GetIndex(IEnumerable fields)
@@ -126,7 +127,7 @@ public IReadOnlyList GetIndexesContainingAllData()
{
return IsLocked
? indexesContainingAllData
- : FindIndexesContainingAllData().AsReadOnly();
+ : FindIndexesContainingAllData().AsSafeWrapper();
}
private List FindIndexesContainingAllData()
diff --git a/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs b/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs
index a7e0f8abd1..c5d0e9692e 100644
--- a/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs
+++ b/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs
@@ -52,7 +52,6 @@ public sealed class TypeInfo : SchemaMappedNode
private IReadOnlyList removalSequence;
private IReadOnlyList versionFields;
private IReadOnlyList versionColumns;
- private IList validators;
private Type underlyingType;
private HierarchyInfo hierarchy;
private int typeId = NoTypeId;
@@ -504,14 +503,7 @@ public IDictionary, FieldInfo> StructureFieldMapping
/// Gets instances
/// associated with this type.
///
- public IList Validators
- {
- get { return validators; }
- internal set {
- EnsureNotLocked();
- validators = value;
- }
- }
+ public IReadOnlyList Validators { get; init; }
///
/// Gets value indicating if this type has validators (including field validators).
@@ -565,7 +557,7 @@ public IEnumerable GetTargetAssociations()
if (!IsLocked) {
return result;
}
- targetAssociations = result.ToList().AsReadOnly();
+ targetAssociations = result.ToList().AsSafeWrapper();
}
return targetAssociations;
}
@@ -580,7 +572,7 @@ public IEnumerable GetOwnerAssociations()
if (!IsLocked) {
return result;
}
- ownerAssociations = result.ToList().AsReadOnly();
+ ownerAssociations = result.ToList().AsSafeWrapper();
}
return ownerAssociations;
}
@@ -694,7 +686,7 @@ public override void UpdateState()
}
}
- HasValidators = validators.Count > 0 || fields.Any(f => f.HasValidators);
+ HasValidators = Validators.Count > 0 || fields.Any(static f => f.HasValidators);
// Selecting master parts from paired associations & single associations
var associations = model.Associations.Find(this)
@@ -753,7 +745,7 @@ public override void UpdateState()
var sortedRemovalSequence = sequence.Where(a => a.Ancestors.Count > 0).ToList();
if (sortedRemovalSequence.Count == 0) {
- removalSequence = sequence.AsReadOnly();
+ removalSequence = sequence.AsSafeWrapper();
}
else {
var sequenceSize = sequence.Count;
@@ -761,7 +753,7 @@ public override void UpdateState()
sortedRemovalSequence.Capacity = sequenceSize;
}
sortedRemovalSequence.AddRange(sequence.Where(a => a.Ancestors.Count == 0));
- removalSequence = sortedRemovalSequence.AsReadOnly();
+ removalSequence = sortedRemovalSequence.AsSafeWrapper();
}
}
@@ -782,8 +774,6 @@ public override void Lock(bool recursive)
if (!recursive)
return;
- validators = Array.AsReadOnly(validators.ToArray());
-
affectedIndexes.Lock(true);
indexes.Lock(true);
columns.Lock(true);
diff --git a/Orm/Xtensive.Orm/Orm/Providers/Persister.cs b/Orm/Xtensive.Orm/Orm/Providers/Persister.cs
index 6d6733d023..f36c539733 100644
--- a/Orm/Xtensive.Orm/Orm/Providers/Persister.cs
+++ b/Orm/Xtensive.Orm/Orm/Providers/Persister.cs
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Xtensive LLC.
+// Copyright (C) 2012 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Created by: Denis Krjuchkov
@@ -93,11 +93,10 @@ private SqlPersistTask CreateRemoveTask(PersistAction action, bool validateVersi
}
}
- private ICollection GetOrBuildRequest(StorageNode node, PersistRequestBuilderTask task)
+ private IReadOnlyList GetOrBuildRequest(StorageNode node, PersistRequestBuilderTask task)
{
var cache = node.PersistRequestCache;
- ICollection result;
- if (cache.TryGetValue(task, out result))
+ if (cache.TryGetValue(task, out var result))
return result;
result = requestBuilder.Build(node, task);
return cache.TryAdd(task, result) ? result : cache[task];
diff --git a/Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestBuilder.cs b/Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestBuilder.cs
index 9f9c3f0abf..fdac0b9cb8 100644
--- a/Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestBuilder.cs
+++ b/Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestBuilder.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
+using Xtensive.Core;
using Xtensive.Orm.Configuration;
using Xtensive.Orm.Model;
using Xtensive.Sql;
@@ -23,7 +24,7 @@ public class PersistRequestBuilder : DomainBoundHandler
private ProviderInfo providerInfo;
private StorageDriver driver;
- internal ICollection Build(StorageNode node, PersistRequestBuilderTask task)
+ internal IReadOnlyList Build(StorageNode node, PersistRequestBuilderTask task)
{
var context = new PersistRequestBuilderContext(task, node.Mapping, node.Configuration);
List result;
@@ -52,14 +53,14 @@ internal ICollection Build(StorageNode node, PersistRequestBuild
}
var batchRequest = CreatePersistRequest(batch, bindings, node.Configuration);
batchRequest.Prepare();
- return new List {batchRequest}.AsReadOnly();
+ return new List { batchRequest }.AsSafeWrapper();
}
foreach (var item in result) {
item.Prepare();
}
- return result.AsReadOnly();
+ return result.AsSafeWrapper();
}
protected virtual List BuildInsertRequest(PersistRequestBuilderContext context)
diff --git a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Index.cs b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Index.cs
index e6af744980..b2234207e0 100644
--- a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Index.cs
+++ b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Index.cs
@@ -224,7 +224,7 @@ private QueryAndBindings BuildFilteredQuery(IndexInfo index)
SqlExpression filter = null;
var type = index.ReflectedType;
var discriminatorMap = type.Hierarchy.TypeDiscriminatorMap;
- var filterByTypes = index.FilterByTypes.ToList();
+ var filterByTypes = index.FilterByTypes;
var filterByTypesCount = filterByTypes.Count;
if (underlyingIndex.IsTyped && discriminatorMap != null) {
var columnType = discriminatorMap.Column.ValueType;
diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/SelectProvider.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/SelectProvider.cs
index 181e0054d4..5cfd06f4d0 100644
--- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/SelectProvider.cs
+++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/SelectProvider.cs
@@ -44,17 +44,7 @@ protected override string ParametersToString()
public SelectProvider(CompilableProvider provider, IReadOnlyList columnIndexes)
: base(ProviderType.Select, provider)
{
- switch (columnIndexes) {
- case int[] indexArray:
- ColumnIndexes = Array.AsReadOnly(indexArray);
- break;
- case List indexList:
- ColumnIndexes = indexList.AsReadOnly();
- break;
- default:
- ColumnIndexes = columnIndexes;
- break;
- }
+ ColumnIndexes = columnIndexes.AsSafeWrapper();
Initialize();
}
diff --git a/Orm/Xtensive.Orm/Orm/Rse/Transformation/ColumnMappingInspector.cs b/Orm/Xtensive.Orm/Orm/Rse/Transformation/ColumnMappingInspector.cs
index 257716a6a2..d346556d93 100644
--- a/Orm/Xtensive.Orm/Orm/Rse/Transformation/ColumnMappingInspector.cs
+++ b/Orm/Xtensive.Orm/Orm/Rse/Transformation/ColumnMappingInspector.cs
@@ -78,7 +78,7 @@ protected override Provider VisitSelect(SelectProvider provider)
mappings[provider] = newMappings;
return source == provider.Source
? provider
- : new SelectProvider(source, indexColumns.ToArray());
+ : new SelectProvider(source, indexColumns);
}
///
@@ -122,7 +122,7 @@ protected override Provider VisitJoin(JoinProvider provider)
{
// split
- SplitMappings(provider, out var leftMapping, out var rightMapping);
+ var (leftMapping, rightMapping) = SplitMappings(provider);
leftMapping = Merge(leftMapping, provider.EqualIndexes.Select(p => p.First));
rightMapping = Merge(rightMapping, provider.EqualIndexes.Select(p => p.Second));
@@ -148,7 +148,7 @@ protected override Provider VisitJoin(JoinProvider provider)
protected override Provider VisitPredicateJoin(PredicateJoinProvider provider)
{
- SplitMappings(provider, out var leftMapping, out var rightMapping);
+ var (leftMapping, rightMapping) = SplitMappings(provider);
leftMapping.AddRange(mappingsGatherer.Gather(provider.Predicate,
provider.Predicate.Parameters[0]));
@@ -190,7 +190,7 @@ protected override Provider VisitApply(ApplyProvider provider)
{
// split
- SplitMappings(provider, out var leftMapping, out var rightMapping);
+ var (leftMapping, rightMapping) = SplitMappings(provider);
var applyParameter = provider.ApplyParameter;
var currentOuterUsages = new List();
@@ -217,12 +217,12 @@ protected override Provider VisitApply(ApplyProvider provider)
_ = outerColumnUsages.Remove(applyParameter);
var pair = OverrideRightApplySource(provider, newRightProvider, rightMapping);
- if (pair.First == null) {
+ if (pair.compilableProvider == null) {
rightMapping = mappings[provider.Right];
}
else {
- newRightProvider = pair.First;
- rightMapping = pair.Second;
+ newRightProvider = pair.compilableProvider;
+ rightMapping = pair.mapping;
}
RestoreMappings(oldMappings);
@@ -400,9 +400,8 @@ private static CompilableProvider BuildSetOperationSource(CompilableProvider pro
return new SelectProvider(provider, columns);
}
- protected virtual Pair> OverrideRightApplySource(ApplyProvider applyProvider,
- CompilableProvider provider, List requestedMapping) =>
- new Pair>(provider, requestedMapping);
+ protected virtual (CompilableProvider compilableProvider, List mapping) OverrideRightApplySource(ApplyProvider applyProvider, CompilableProvider provider, List requestedMapping) =>
+ (provider, requestedMapping);
#endregion
@@ -441,20 +440,21 @@ private static List MergeMappings(Provider originalLeft, List leftMap,
return result;
}
- private void SplitMappings(BinaryProvider provider, out List leftMapping, out List rightMapping)
+ private (List leftMapping, List rightMapping) SplitMappings(BinaryProvider provider)
{
var binaryMapping = mappings[provider];
- leftMapping = new List(binaryMapping.Count);
+ var leftMapping = new List(binaryMapping.Count);
var leftCount = provider.Left.Header.Length;
var index = 0;
while (index < binaryMapping.Count && binaryMapping[index] < leftCount) {
leftMapping.Add(binaryMapping[index]);
index++;
}
- rightMapping = new List(binaryMapping.Count - index);
+ var rightMapping = new List(binaryMapping.Count - index);
for (var i = index; i < binaryMapping.Count; i++) {
rightMapping.Add(binaryMapping[i] - leftCount);
}
+ return (leftMapping, rightMapping);
}
private void RegisterOuterMapping(ApplyParameter parameter, int value)
@@ -508,7 +508,7 @@ private void VisitJoin(ref List leftMapping, ref CompilableProvider left, r
private Dictionary> ReplaceMappings(Provider firstNewKey, List firstNewValue)
{
var oldMappings = mappings;
- mappings = new Dictionary> {{firstNewKey, firstNewValue}};
+ mappings = new() { { firstNewKey, firstNewValue } };
return oldMappings;
}
diff --git a/Orm/Xtensive.Orm/Orm/Rse/Transformation/RedundantColumnRemover.cs b/Orm/Xtensive.Orm/Orm/Rse/Transformation/RedundantColumnRemover.cs
index 9ef551e717..39fe411f27 100644
--- a/Orm/Xtensive.Orm/Orm/Rse/Transformation/RedundantColumnRemover.cs
+++ b/Orm/Xtensive.Orm/Orm/Rse/Transformation/RedundantColumnRemover.cs
@@ -27,13 +27,13 @@ internal sealed class RedundantColumnRemover : ColumnMappingInspector
&& methodInfo.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == WellKnownTypes.FuncOfTArgTResultType)
.CachedMakeGenericMethod(WellKnownOrmTypes.Tuple, WellKnownOrmTypes.Tuple);
- protected override Pair> OverrideRightApplySource(ApplyProvider applyProvider, CompilableProvider provider, List requestedMapping)
+ protected override (CompilableProvider, List) OverrideRightApplySource(ApplyProvider applyProvider, CompilableProvider provider, List requestedMapping)
{
var currentMapping = mappings[applyProvider.Right];
if (currentMapping.SequenceEqual(requestedMapping))
return base.OverrideRightApplySource(applyProvider, provider, requestedMapping);
var selectProvider = new SelectProvider(provider, requestedMapping.ToArray());
- return new Pair>(selectProvider, requestedMapping);
+ return (selectProvider, requestedMapping);
}
protected override Provider VisitRaw(RawProvider provider)
diff --git a/Orm/Xtensive.Orm/Orm/StorageNode.cs b/Orm/Xtensive.Orm/Orm/StorageNode.cs
index 20ac4d09b1..8c339a341e 100644
--- a/Orm/Xtensive.Orm/Orm/StorageNode.cs
+++ b/Orm/Xtensive.Orm/Orm/StorageNode.cs
@@ -72,7 +72,7 @@ public sealed class StorageNode : ISessionSource
///
internal ConcurrentDictionary)> RefsToEntityQueryCache { get; }
internal ConcurrentDictionary KeySequencesCache { get; }
- internal ConcurrentDictionary> PersistRequestCache { get; }
+ internal ConcurrentDictionary> PersistRequestCache { get; } = new();
///
public Session OpenSession() =>
@@ -127,7 +127,6 @@ internal StorageNode(Domain domain, NodeConfiguration configuration, ModelMappin
EntitySetTypeStateCache = new ConcurrentDictionary();
RefsToEntityQueryCache = new ConcurrentDictionary)>();
KeySequencesCache = new ConcurrentDictionary();
- PersistRequestCache = new ConcurrentDictionary>();
this.domain = domain;
Configuration = configuration;
diff --git a/Orm/Xtensive.Orm/Reflection/InterfaceMapping.cs b/Orm/Xtensive.Orm/Reflection/InterfaceMapping.cs
index a2b3055a32..fe7e9730de 100644
--- a/Orm/Xtensive.Orm/Reflection/InterfaceMapping.cs
+++ b/Orm/Xtensive.Orm/Reflection/InterfaceMapping.cs
@@ -10,6 +10,7 @@
using ReflectionInterfaceMapping=System.Reflection.InterfaceMapping;
using System.Linq;
using System.Collections.Generic;
+using Xtensive.Core;
namespace Xtensive.Reflection
{
@@ -50,8 +51,8 @@ public InterfaceMapping(ReflectionInterfaceMapping source)
{
TargetType = source.TargetType;
InterfaceType = source.InterfaceType;
- TargetMethods = Array.AsReadOnly(source.TargetMethods);
- InterfaceMethods = Array.AsReadOnly(source.InterfaceMethods);
+ TargetMethods = source.TargetMethods.AsSafeWrapper();
+ InterfaceMethods = source.InterfaceMethods.AsSafeWrapper();
}
}
}
\ No newline at end of file
diff --git a/Orm/Xtensive.Orm/Reflection/TypeHelper.cs b/Orm/Xtensive.Orm/Reflection/TypeHelper.cs
index 601d9b111f..31c8436250 100644
--- a/Orm/Xtensive.Orm/Reflection/TypeHelper.cs
+++ b/Orm/Xtensive.Orm/Reflection/TypeHelper.cs
@@ -703,8 +703,8 @@ from pair in zipped
///
/// The types to sort.
/// The list of ordered by their inheritance.
- public static List OrderByInheritance(this IEnumerable types) =>
- TopologicalSorter.Sort(types, (t1, t2) => t1.IsAssignableFrom(t2));
+ public static IEnumerable OrderByInheritance(this IEnumerable types) =>
+ TopologicalSorter.Sort(types, static (t1, t2) => t1.IsAssignableFrom(t2));
///
/// Fast analogue of .
@@ -723,7 +723,7 @@ public static InterfaceMapping GetInterfaceMapFast(this Type type, Type targetIn
/// The type to get the interfaces of.
[Obsolete("Use GetInterfacesOrderByInheritance instead")]
public static Type[] GetInterfaces(this Type type) =>
- OrderedInterfaces.GetOrAdd(type, t => t.GetInterfaces().OrderByInheritance().ToArray());
+ OrderedInterfaces.GetOrAdd(type, static t => t.GetInterfaces().OrderByInheritance().ToArray());
///
/// Gets the interfaces of the specified type.
@@ -731,7 +731,7 @@ public static Type[] GetInterfaces(this Type type) =>
///
/// The type to get the interfaces of.
public static Type[] GetInterfacesOrderByInheritance(this Type type) =>
- OrderedInterfaces.GetOrAdd(type, t => t.GetInterfaces().OrderByInheritance().ToArray());
+ OrderedInterfaces.GetOrAdd(type, static t => t.GetInterfaces().OrderByInheritance().ToArray());
///
/// Gets the sequence of type itself, all its base types and interfaces.
diff --git a/Orm/Xtensive.Orm/Sorting/Node.cs b/Orm/Xtensive.Orm/Sorting/Node.cs
index b6a882c8f4..0818aa3698 100644
--- a/Orm/Xtensive.Orm/Sorting/Node.cs
+++ b/Orm/Xtensive.Orm/Sorting/Node.cs
@@ -10,7 +10,6 @@
using System.Linq;
using Xtensive.Core;
-
namespace Xtensive.Sorting
{
///
@@ -22,9 +21,9 @@ namespace Xtensive.Sorting
public class Node
{
private List> incomingConnections;
- private ReadOnlyCollection> incomingConnectionsReadOnlyList;
+ private IReadOnlyList> incomingConnectionsReadOnlyList;
private List> outgoingConnections;
- private ReadOnlyCollection> outgoingConnectionsReadOnlyList;
+ private IReadOnlyList> outgoingConnectionsReadOnlyList;
///
/// Gets node item.
@@ -166,18 +165,14 @@ public IEnumerable> RemoveConnections
private void EnsureIncomingConnections()
{
- if (incomingConnectionsReadOnlyList==null) {
- incomingConnections = new List>();
- incomingConnectionsReadOnlyList = incomingConnections.AsReadOnly();
- }
+ incomingConnectionsReadOnlyList ??=
+ (incomingConnections = new List>()).AsSafeWrapper();
}
private void EnsureOutgoingConnections()
{
- if (outgoingConnectionsReadOnlyList==null) {
- outgoingConnections = new List>();
- outgoingConnectionsReadOnlyList = outgoingConnections.AsReadOnly();
- }
+ outgoingConnectionsReadOnlyList ??=
+ (outgoingConnections = new List>()).AsSafeWrapper();
}
// Constructors
diff --git a/Orm/Xtensive.Orm/Sorting/TopologicalSorter.cs b/Orm/Xtensive.Orm/Sorting/TopologicalSorter.cs
index 64566109dc..284b36011b 100644
--- a/Orm/Xtensive.Orm/Sorting/TopologicalSorter.cs
+++ b/Orm/Xtensive.Orm/Sorting/TopologicalSorter.cs
@@ -29,7 +29,7 @@ public static class TopologicalSorter
/// Sorting result, if there were no loops;
/// otherwise, .
///
- public static List Sort(IEnumerable items, Predicate connector)
+ public static IEnumerable Sort(IEnumerable items, Predicate connector)
{
List> loops;
return Sort(items, connector, out loops);
@@ -48,7 +48,7 @@ public static List Sort(IEnumerable items, Pred
/// otherwise, .
/// In this case will contain only the loop edges.
///
- public static List Sort(IEnumerable items, Predicate connector, out List> loops)
+ public static IEnumerable Sort(IEnumerable items, Predicate connector, out List> loops)
{
ArgumentValidator.EnsureArgumentNotNull(items, "items");
ArgumentValidator.EnsureArgumentNotNull(connector, "connector");
@@ -101,7 +101,7 @@ public static List Sort(IEnumerable items, Pred
/// Sorting result, if there were no loops;
/// otherwise, .
/// In this case will contain only the loop edges.
- public static List Sort(List> nodes, out List> loops)
+ public static IEnumerable Sort(List> nodes, out List> loops)
{
ArgumentValidator.EnsureArgumentNotNull(nodes, "nodes");
var head = new Queue();
@@ -136,7 +136,7 @@ public static List Sort(List