diff --git a/EFCore.sln.DotSettings b/EFCore.sln.DotSettings index b8b7f701254..0225629c00b 100644 --- a/EFCore.sln.DotSettings +++ b/EFCore.sln.DotSettings @@ -113,6 +113,7 @@ Required Required Required + Join ExplicitlyTyped True False diff --git a/src/EFCore.SqlServer.HierarchyId/EFCore.SqlServer.HierarchyId.csproj b/src/EFCore.SqlServer.HierarchyId/EFCore.SqlServer.HierarchyId.csproj index 88797f4922e..24fc80cb15c 100644 --- a/src/EFCore.SqlServer.HierarchyId/EFCore.SqlServer.HierarchyId.csproj +++ b/src/EFCore.SqlServer.HierarchyId/EFCore.SqlServer.HierarchyId.csproj @@ -23,8 +23,9 @@ - + + diff --git a/src/EFCore/ChangeTracking/CollectionEntry.cs b/src/EFCore/ChangeTracking/CollectionEntry.cs index 648ce048907..859ff54a344 100644 --- a/src/EFCore/ChangeTracking/CollectionEntry.cs +++ b/src/EFCore/ChangeTracking/CollectionEntry.cs @@ -25,8 +25,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; /// public class CollectionEntry : NavigationEntry { - private ICollectionLoader? _loader; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -164,11 +162,12 @@ public override bool IsModified { var joinEntityType = skipNavigation.JoinEntityType; var foreignKey = skipNavigation.ForeignKey; - foreach (var joinEntry in stateManager - .GetEntriesForState(added: !value, modified: !value, deleted: !value, unchanged: value).Where( - e => e.EntityType == joinEntityType - && stateManager.FindPrincipal(e, foreignKey) == InternalEntry) - .ToList()) + var joinEntries = stateManager + .GetEntriesForState(added: !value, modified: !value, deleted: !value, unchanged: value) + .Where(e => e.EntityType == joinEntityType + && stateManager.FindPrincipal(e, foreignKey) == InternalEntry) + .ToList(); + foreach (var joinEntry in joinEntries) { joinEntry.SetEntityState(value ? EntityState.Modified : EntityState.Unchanged); } @@ -335,8 +334,9 @@ private void EnsureInitialized() ? null : InternalEntry.StateManager.GetOrCreateEntry(entity, Metadata.TargetEntityType); + [field: AllowNull, MaybeNull] private ICollectionLoader TargetLoader - => _loader ??= Metadata is IRuntimeSkipNavigation skipNavigation + => field ??= Metadata is IRuntimeSkipNavigation skipNavigation ? skipNavigation.GetManyToManyLoader() : new EntityFinderCollectionLoaderAdapter( InternalEntry.StateManager.CreateEntityFinder(Metadata.TargetEntityType), diff --git a/src/EFCore/ChangeTracking/ComplexCollectionEntry.cs b/src/EFCore/ChangeTracking/ComplexCollectionEntry.cs index 2cdb30888d6..3f21861c3d8 100644 --- a/src/EFCore/ChangeTracking/ComplexCollectionEntry.cs +++ b/src/EFCore/ChangeTracking/ComplexCollectionEntry.cs @@ -79,18 +79,18 @@ private void DetectChanges() } /// - /// Gets a for the complex item at the specified ordinal. + /// Gets a for the complex item at the specified ordinal. /// /// The ordinal of the complex item to access. - /// A for the complex item at the specified ordinal. + /// A for the complex item at the specified ordinal. public virtual ComplexElementEntry this[int ordinal] => new(InternalEntry.GetComplexCollectionEntry(Metadata, ordinal)); /// - /// Gets a for the original complex item at the specified ordinal. + /// Gets a for the original complex item at the specified ordinal. /// /// The original ordinal of the complex item to access. - /// A for the complex item at the specified original ordinal. + /// A for the complex item at the specified original ordinal. public virtual ComplexElementEntry GetOriginalEntry(int ordinal) => new(InternalEntry.GetComplexCollectionOriginalEntry(Metadata, ordinal)); diff --git a/src/EFCore/ChangeTracking/ComplexCollectionEntry`.cs b/src/EFCore/ChangeTracking/ComplexCollectionEntry`.cs index 9ee84858943..29ee014f627 100644 --- a/src/EFCore/ChangeTracking/ComplexCollectionEntry`.cs +++ b/src/EFCore/ChangeTracking/ComplexCollectionEntry`.cs @@ -66,18 +66,18 @@ public override EntityEntry EntityEntry } /// - /// Gets a for the complex item at the specified ordinal. + /// Gets a for the complex item at the specified ordinal. /// /// The ordinal of the complex item to access. - /// A for the complex item at the specified ordinal. + /// A for the complex item at the specified ordinal. public override ComplexElementEntry this[int ordinal] => new(InternalEntry.GetComplexCollectionEntry(Metadata, ordinal)); /// - /// Gets a for the complex item at the specified original ordinal. + /// Gets a for the complex item at the specified original ordinal. /// /// The original ordinal of the complex item to access. - /// A for the original complex item at the specified ordinal. + /// A for the original complex item at the specified ordinal. public override ComplexElementEntry GetOriginalEntry(int ordinal) => new(InternalEntry.GetComplexCollectionOriginalEntry(Metadata, ordinal)); } diff --git a/src/EFCore/ChangeTracking/ComplexElementEntry.cs b/src/EFCore/ChangeTracking/ComplexElementEntry.cs index 083f9eb52c4..b276a48bafb 100644 --- a/src/EFCore/ChangeTracking/ComplexElementEntry.cs +++ b/src/EFCore/ChangeTracking/ComplexElementEntry.cs @@ -33,9 +33,7 @@ public class ComplexElementEntry : IInfrastructure /// [EntityFrameworkInternal] public ComplexElementEntry(InternalComplexEntry internalEntry) - { - InternalEntry = internalEntry; - } + => InternalEntry = internalEntry; /// /// Gets or sets a value indicating whether any of the properties of the complex type have been modified @@ -85,7 +83,8 @@ public virtual bool IsModified /// /// Gets the metadata that describes the facets of this property and how it maps to the database. /// - public virtual IComplexProperty Metadata => InternalEntry.ComplexProperty; + public virtual IComplexProperty Metadata + => InternalEntry.ComplexProperty; /// /// Gets or sets the value currently assigned to this property. If the current value is set using this property, @@ -273,7 +272,8 @@ public virtual ComplexCollectionEntry ComplexCollection(string propertyName) /// examples. /// public virtual IEnumerable ComplexCollections - => Metadata.ComplexType.GetComplexProperties().Where(p => p.IsCollection).Select(property => new ComplexCollectionEntry(InternalEntry, property)); + => Metadata.ComplexType.GetComplexProperties().Where(p => p.IsCollection) + .Select(property => new ComplexCollectionEntry(InternalEntry, property)); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/ChangeTracking/ComplexPropertyEntry.cs b/src/EFCore/ChangeTracking/ComplexPropertyEntry.cs index b1424b02427..02e6e317f35 100644 --- a/src/EFCore/ChangeTracking/ComplexPropertyEntry.cs +++ b/src/EFCore/ChangeTracking/ComplexPropertyEntry.cs @@ -166,7 +166,8 @@ public virtual ComplexPropertyEntry ComplexProperty(string propertyName) /// examples. /// public virtual IEnumerable ComplexProperties - => Metadata.ComplexType.GetComplexProperties().Where(p => !p.IsCollection).Select(property => new ComplexPropertyEntry(InternalEntry, property)); + => Metadata.ComplexType.GetComplexProperties().Where(p => !p.IsCollection) + .Select(property => new ComplexPropertyEntry(InternalEntry, property)); /// /// Provides access to change tracking information and operations for a given collection property of a complex type on this complex type. @@ -208,5 +209,6 @@ public virtual ComplexCollectionEntry ComplexCollection(string propertyName) /// examples. /// public virtual IEnumerable ComplexCollections - => Metadata.ComplexType.GetComplexProperties().Where(p => p.IsCollection).Select(property => new ComplexCollectionEntry(InternalEntry, property)); + => Metadata.ComplexType.GetComplexProperties().Where(p => p.IsCollection) + .Select(property => new ComplexCollectionEntry(InternalEntry, property)); } diff --git a/src/EFCore/ChangeTracking/DetectEntityChangesEventArgs.cs b/src/EFCore/ChangeTracking/DetectEntityChangesEventArgs.cs index 8e8283182a4..daf8cfea94c 100644 --- a/src/EFCore/ChangeTracking/DetectEntityChangesEventArgs.cs +++ b/src/EFCore/ChangeTracking/DetectEntityChangesEventArgs.cs @@ -14,7 +14,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; public class DetectEntityChangesEventArgs : DetectChangesEventArgs { private readonly InternalEntityEntry _internalEntityEntry; - private EntityEntry? _entry; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -29,6 +28,7 @@ public DetectEntityChangesEventArgs(InternalEntityEntry internalEntityEntry) /// /// The for the entity. /// + [field: AllowNull, MaybeNull] public virtual EntityEntry Entry - => _entry ??= new EntityEntry(_internalEntityEntry); + => field ??= new EntityEntry(_internalEntityEntry); } diff --git a/src/EFCore/ChangeTracking/DetectedEntityChangesEventArgs.cs b/src/EFCore/ChangeTracking/DetectedEntityChangesEventArgs.cs index 8d45c6ee6dd..6618495cda9 100644 --- a/src/EFCore/ChangeTracking/DetectedEntityChangesEventArgs.cs +++ b/src/EFCore/ChangeTracking/DetectedEntityChangesEventArgs.cs @@ -14,7 +14,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; public class DetectedEntityChangesEventArgs : DetectedChangesEventArgs { private readonly InternalEntityEntry _internalEntityEntry; - private EntityEntry? _entry; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -32,6 +31,7 @@ public DetectedEntityChangesEventArgs( /// /// The for the entity. /// + [field: AllowNull, MaybeNull] public virtual EntityEntry Entry - => _entry ??= new EntityEntry(_internalEntityEntry); + => field ??= new EntityEntry(_internalEntityEntry); } diff --git a/src/EFCore/ChangeTracking/EntityEntry.cs b/src/EFCore/ChangeTracking/EntityEntry.cs index 91299a60a45..a2d1e5812c7 100644 --- a/src/EFCore/ChangeTracking/EntityEntry.cs +++ b/src/EFCore/ChangeTracking/EntityEntry.cs @@ -25,7 +25,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; public class EntityEntry : IInfrastructure { private static readonly int MaxEntityState = Enum.GetValuesAsUnderlyingType().Cast().Max(); - private IEntityFinder? _finder; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -277,10 +276,9 @@ public virtual IEnumerable Navigations var entityType = InternalEntry.EntityType; return entityType.GetNavigations() .Concat(entityType.GetSkipNavigations()) - .Select( - navigation => navigation.IsCollection - ? (NavigationEntry)new CollectionEntry(InternalEntry, navigation) - : new ReferenceEntry(InternalEntry, navigation)); + .Select(navigation => navigation.IsCollection + ? (NavigationEntry)new CollectionEntry(InternalEntry, navigation) + : new ReferenceEntry(InternalEntry, navigation)); } } @@ -367,7 +365,8 @@ public virtual ComplexPropertyEntry ComplexProperty(string propertyName) /// examples. /// public virtual IEnumerable ComplexProperties - => Metadata.GetComplexProperties().Where(p => !p.IsCollection).Select(property => new ComplexPropertyEntry(InternalEntry, property)); + => Metadata.GetComplexProperties().Where(p => !p.IsCollection) + .Select(property => new ComplexPropertyEntry(InternalEntry, property)); /// /// Provides access to change tracking information and operations for a given collection property of a complex type on this entity. @@ -409,7 +408,8 @@ public virtual ComplexCollectionEntry ComplexCollection(string propertyName) /// examples. /// public virtual IEnumerable ComplexCollections - => Metadata.GetComplexProperties().Where(p => p.IsCollection).Select(property => new ComplexCollectionEntry(InternalEntry, property)); + => Metadata.GetComplexProperties().Where(p => p.IsCollection) + .Select(property => new ComplexCollectionEntry(InternalEntry, property)); /// /// Provides access to change tracking and loading information for a reference (i.e. non-collection) @@ -696,8 +696,9 @@ private void Reload(PropertyValues? storeValues) } } + [field: AllowNull, MaybeNull] private IEntityFinder Finder - => _finder ??= InternalEntry.StateManager.CreateEntityFinder(InternalEntry.EntityType); + => field ??= InternalEntry.StateManager.CreateEntityFinder(InternalEntry.EntityType); /// /// Returns a string that represents the current object. diff --git a/src/EFCore/ChangeTracking/EntityEntryEventArgs.cs b/src/EFCore/ChangeTracking/EntityEntryEventArgs.cs index 41404ca21dc..cbdd9a605eb 100644 --- a/src/EFCore/ChangeTracking/EntityEntryEventArgs.cs +++ b/src/EFCore/ChangeTracking/EntityEntryEventArgs.cs @@ -15,7 +15,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; public class EntityEntryEventArgs : EventArgs { private readonly InternalEntityEntry _internalEntityEntry; - private EntityEntry? _entry; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -31,6 +30,7 @@ public EntityEntryEventArgs( /// /// The for the entity. /// + [field: AllowNull, MaybeNull] public virtual EntityEntry Entry - => _entry ??= new EntityEntry(_internalEntityEntry); + => field ??= new EntityEntry(_internalEntityEntry); } diff --git a/src/EFCore/ChangeTracking/EntityEntryGraphNode.cs b/src/EFCore/ChangeTracking/EntityEntryGraphNode.cs index c4e82161709..a3266adf990 100644 --- a/src/EFCore/ChangeTracking/EntityEntryGraphNode.cs +++ b/src/EFCore/ChangeTracking/EntityEntryGraphNode.cs @@ -28,8 +28,7 @@ public class EntityEntryGraphNode : IInfrastructure /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [DebuggerStepThrough] - [EntityFrameworkInternal] + [DebuggerStepThrough, EntityFrameworkInternal] public EntityEntryGraphNode( InternalEntityEntry entry, InternalEntityEntry? sourceEntry, diff --git a/src/EFCore/ChangeTracking/EntityEntryGraphNode`.cs b/src/EFCore/ChangeTracking/EntityEntryGraphNode`.cs index 5758247ee7e..cedbe7e06d8 100644 --- a/src/EFCore/ChangeTracking/EntityEntryGraphNode`.cs +++ b/src/EFCore/ChangeTracking/EntityEntryGraphNode`.cs @@ -20,8 +20,7 @@ public class EntityEntryGraphNode : EntityEntryGraphNode /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [DebuggerStepThrough] - [EntityFrameworkInternal] + [DebuggerStepThrough, EntityFrameworkInternal] public EntityEntryGraphNode( InternalEntityEntry entry, TState state, diff --git a/src/EFCore/ChangeTracking/GeometryValueComparer.cs b/src/EFCore/ChangeTracking/GeometryValueComparer.cs index 29594894c2e..1d6a78070ab 100644 --- a/src/EFCore/ChangeTracking/GeometryValueComparer.cs +++ b/src/EFCore/ChangeTracking/GeometryValueComparer.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking; /// @@ -12,7 +10,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; /// See EF Core value comparers for more information and examples. /// public class GeometryValueComparer - <[DynamicallyAccessedMembers( +<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] TGeometry> @@ -43,7 +41,7 @@ public GeometryValueComparer() return Expression.Lambda>( Expression.Block( typeof(bool), - new[] { x, y, xNull, yNull }, + [x, y, xNull, yNull], Expression.Assign(x, left), Expression.Assign(y, right), Expression.Assign(xNull, Expression.ReferenceEqual(x, nullExpression)), diff --git a/src/EFCore/ChangeTracking/IDependentKeyValueFactory`.cs b/src/EFCore/ChangeTracking/IDependentKeyValueFactory`.cs index b5640e33cdd..c8a5a151dbf 100644 --- a/src/EFCore/ChangeTracking/IDependentKeyValueFactory`.cs +++ b/src/EFCore/ChangeTracking/IDependentKeyValueFactory`.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; namespace Microsoft.EntityFrameworkCore.ChangeTracking; diff --git a/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs b/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs index 3c388b510df..e4fe149a005 100644 --- a/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs +++ b/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs @@ -41,11 +41,6 @@ public override object ToObject() var structuralObject = StructuralType.GetOrCreateMaterializer(MaterializerSource)( new MaterializationContext(new ValueBuffer(_values), InternalEntry.Context)); - if (_complexCollectionValues == null) - { - return structuralObject; - } - for (var i = 0; i < _complexCollectionValues.Length; i++) { var propertyValuesList = _complexCollectionValues[i]; @@ -54,9 +49,9 @@ public override object ToObject() continue; } - var complexProperty = ComplexCollectionProperties[i]; - Check.DebugAssert(!complexProperty.IsShadowProperty(), + Check.DebugAssert( + !complexProperty.IsShadowProperty(), $"Shadow complex property {complexProperty.Name} is not supported. Issue #31243"); var list = (IList)((IRuntimeComplexProperty)complexProperty).GetIndexedCollectionAccessor().Create(propertyValuesList.Count); structuralObject = ((IRuntimeComplexProperty)complexProperty).GetSetter().SetClrValue(structuralObject, list); @@ -138,21 +133,21 @@ public override PropertyValues Clone() Array.Copy(_values, copies, _values.Length); var clone = new ArrayPropertyValues(InternalEntry, copies); - if (_complexCollectionValues != null) + for (var i = 0; i < _complexCollectionValues.Length; i++) { - for (var i = 0; i < _complexCollectionValues.Length; i++) + var list = _complexCollectionValues[i]; + if (list == null) { - var list = _complexCollectionValues[i]; - if (list != null) - { - var clonedList = new List(); - foreach (var propertyValues in list) - { - clonedList.Add((ArrayPropertyValues?)propertyValues?.Clone()); - } - clone._complexCollectionValues[i] = clonedList; - } + continue; + } + + var clonedList = new List(); + foreach (var propertyValues in list) + { + clonedList.Add((ArrayPropertyValues?)propertyValues?.Clone()); } + + clone._complexCollectionValues[i] = clonedList; } return clone; @@ -190,12 +185,12 @@ public override object? this[string propertyName] { get { - if (StructuralType.FindProperty(propertyName) is IProperty property) + if (StructuralType.FindProperty(propertyName) is { } property) { return _values[property.GetIndex()]; } - if (StructuralType.FindComplexProperty(propertyName) is IComplexProperty complexProperty) + if (StructuralType.FindComplexProperty(propertyName) is { } complexProperty) { return this[complexProperty]; } @@ -205,33 +200,31 @@ public override object? this[string propertyName] } set { - if (StructuralType.FindProperty(propertyName) is IProperty property) + if (StructuralType.FindProperty(propertyName) is { } property) { SetValue(property.GetIndex(), value); return; } - if (StructuralType.FindComplexProperty(propertyName) is IComplexProperty complexProperty) + if (StructuralType.FindComplexProperty(propertyName) is { } complexProperty) { CheckCollection(complexProperty); - if (value is null) - { - _complexCollectionValues[complexProperty.GetIndex()] = null; - } - else if (value is List propertyValuesList) - { - _complexCollectionValues[complexProperty.GetIndex()] = propertyValuesList; - } - else if (value is IList complexCollection) + switch (value) { - this[complexProperty] = complexCollection; - } - else - { - throw new InvalidOperationException( - CoreStrings.ComplexPropertyValueNotList( - complexProperty.Name, complexProperty.ClrType, value.GetType().ShortDisplayName())); + case null: + _complexCollectionValues[complexProperty.GetIndex()] = null; + break; + case List propertyValuesList: + _complexCollectionValues[complexProperty.GetIndex()] = propertyValuesList; + break; + case IList complexCollection: + this[complexProperty] = complexCollection; + break; + default: + throw new InvalidOperationException( + CoreStrings.ComplexPropertyValueNotList( + complexProperty.Name, complexProperty.ClrType, value.GetType().ShortDisplayName())); } } @@ -269,7 +262,8 @@ public override IList? this[IComplexProperty complexProperty] return null; } - var complexObjectsList = (IList)((IRuntimePropertyBase)complexProperty).GetIndexedCollectionAccessor().Create(propertyValuesList.Count); + var complexObjectsList = (IList)((IRuntimePropertyBase)complexProperty).GetIndexedCollectionAccessor() + .Create(propertyValuesList.Count); foreach (var propertyValues in propertyValuesList) { complexObjectsList.Add(propertyValues?.ToObject()); @@ -281,7 +275,7 @@ public override IList? this[IComplexProperty complexProperty] set => SetComplexCollectionValue(CheckCollection(complexProperty), GetComplexCollectionPropertyValues(complexProperty, value)); } - /// + /// public override void SetValues(IDictionary values) => SetValuesFromDictionary((IRuntimeTypeBase)StructuralType, Check.NotNull(values)); @@ -308,10 +302,12 @@ private void SetValuesFromDictionary(IRuntimeTypeBase structuralType, if (complexValue != null && dictionaryList == null) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionValueNotDictionaryList(complexProperty.Name, complexValue.GetType().ShortDisplayName())); + CoreStrings.ComplexCollectionValueNotDictionaryList( + complexProperty.Name, complexValue.GetType().ShortDisplayName())); } - SetComplexCollectionValue(complexProperty, CreatePropertyValuesFromDictionaryList(complexProperty, dictionaryList)); + SetComplexCollectionValue( + complexProperty, CreatePropertyValuesFromDictionaryList(complexProperty, dictionaryList)); } else { @@ -330,7 +326,9 @@ private void SetValuesFromDictionary(IRuntimeTypeBase structuralType, } } - private List? CreatePropertyValuesFromDictionaryList(IComplexProperty complexProperty, IList? collection) + private List? CreatePropertyValuesFromDictionaryList( + IComplexProperty complexProperty, + IList? collection) { if (collection == null) { @@ -387,7 +385,8 @@ public override TValue GetValue(IProperty property) private void SetValue(int index, object? value) { var property = Properties[index]; - Check.DebugAssert(index == property.GetIndex(), + Check.DebugAssert( + index == property.GetIndex(), $"Property index {property.GetIndex()} does not match the index {index} for the property {property.Name} in the structural type {StructuralType.DisplayName()}"); if (value != null) @@ -428,9 +427,7 @@ private IStructuralTypeMaterializerSource MaterializerSource /// [EntityFrameworkInternal] internal void SetComplexCollectionValue(IComplexProperty complexProperty, List? propertyValuesList) - { - _complexCollectionValues[complexProperty.GetIndex()] = propertyValuesList; - } + => _complexCollectionValues[complexProperty.GetIndex()] = propertyValuesList; private List? GetComplexCollectionPropertyValues(IComplexProperty complexProperty, IList? collection) { @@ -449,7 +446,8 @@ internal void SetComplexCollectionValue(IComplexProperty complexProperty, List(ReferenceEqualityComparer.Instance); var currentCollection = (IList?)entry[complexProperty]; @@ -327,7 +329,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp var originalCollection = (IList?)entry.GetOriginalValue(complexProperty); var changesFound = (currentCollection == null) != (originalCollection == null); - entry.EnsureComplexCollectionEntriesCapacity(complexProperty, currentCollection?.Count ?? 0, originalCollection?.Count ?? 0, trim: false); + entry.EnsureComplexCollectionEntriesCapacity( + complexProperty, currentCollection?.Count ?? 0, originalCollection?.Count ?? 0, trim: false); var originalNulls = new HashSet(); var removed = new Dictionary(ReferenceEqualityComparer.Instance); if (originalCollection != null @@ -354,7 +357,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp originalEntry.SetEntityState(EntityState.Deleted); } - Check.DebugAssert(originalEntry.OriginalOrdinal == i, $"Expected original ordinal {originalEntry.OriginalOrdinal} to be equal to {i}."); + Check.DebugAssert( + originalEntry.OriginalOrdinal == i, $"Expected original ordinal {originalEntry.OriginalOrdinal} to be equal to {i}."); originalEntries[element] = originalEntry; } @@ -381,7 +385,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp // Existing instance found, fix ordinal and check for changes. var originalEntry = originalEntries[element]; - Check.DebugAssert(originalEntry.OriginalOrdinal == originalOrdinal, + Check.DebugAssert( + originalEntry.OriginalOrdinal == originalOrdinal, $"The OriginalOrdinal for entry of the element at original ordinal {originalOrdinal} is {originalEntry.OriginalOrdinal}."); if (originalEntry.Ordinal != i) { @@ -404,7 +409,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp } else { - Check.DebugAssert(originalEntry.Ordinal > i || currentNulls.Contains(originalEntry.Ordinal), + Check.DebugAssert( + originalEntry.Ordinal > i || currentNulls.Contains(originalEntry.Ordinal), $"Expected the entry that was previously at {originalEntry.Ordinal} to have been encountered at an ordinal before {i}."); entry.MoveComplexCollectionEntry(complexProperty, originalEntry.Ordinal, i); @@ -461,7 +467,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp nullEntryOrdinal = j; break; } - else if (newEntry.OriginalOrdinal >= (originalCollection?.Count ?? 0) + + if (newEntry.OriginalOrdinal >= (originalCollection?.Count ?? 0) || newEntry.EntityState == EntityState.Detached) { nullEntryOrdinal = j; @@ -532,10 +539,12 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp } else { - entry.MoveComplexCollectionEntry(complexProperty, currentEntry.OriginalOrdinal, originalOrdinal, original: true); + entry.MoveComplexCollectionEntry( + complexProperty, currentEntry.OriginalOrdinal, originalOrdinal, original: true); } } } + currentEntry.SetEntityState(originalWasNull ? EntityState.Modified : EntityState.Unchanged); } } @@ -566,7 +575,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp } else { - Check.DebugAssert(false, + Check.DebugAssert( + false, $"Expected the entry at {addedOrdinal} to have been removed or matched with a null entry. Current state: {currentEntry.EntityState}."); currentEntry.SetEntityState(EntityState.Added); @@ -589,7 +599,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp foreach (var (removedElement, originalOrdinal) in removed) { var originalEntry = originalEntries[removedElement]; - Check.DebugAssert(originalEntry.OriginalOrdinal == originalOrdinal, + Check.DebugAssert( + originalEntry.OriginalOrdinal == originalOrdinal, $"The OriginalOrdinal for entry of the element at original ordinal {originalOrdinal} is {originalEntry.OriginalOrdinal}."); var newCurrentOrdinal = originalEntry.Ordinal; if (originalEntry.EntityState is EntityState.Unchanged or EntityState.Modified or EntityState.Detached) @@ -639,6 +650,7 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp } } } + changesFound = true; } @@ -676,7 +688,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp continue; } - Check.DebugAssert(nullEntry.EntityState is EntityState.Deleted or EntityState.Detached, + Check.DebugAssert( + nullEntry.EntityState is EntityState.Deleted or EntityState.Detached, $"Expected null entry at {originalNull} to be deleted or detached, current state {nullEntry.EntityState}."); nullEntry.SetEntityState(EntityState.Deleted); changesFound = true; @@ -694,7 +707,8 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp continue; } - Check.DebugAssert(nullEntry.EntityState is EntityState.Added or EntityState.Detached, + Check.DebugAssert( + nullEntry.EntityState is EntityState.Added or EntityState.Detached, $"Expected null entry at {currentNull} to be added or detached, current state {nullEntry.EntityState}."); nullEntry.SetEntityState(EntityState.Added); changesFound = true; @@ -702,11 +716,12 @@ public bool DetectComplexCollectionChanges(InternalEntryBase entry, IComplexProp } // Trim excess entries - entry.EnsureComplexCollectionEntriesCapacity(complexProperty, currentCollection?.Count ?? 0, originalCollection?.Count ?? 0, trim: true); + entry.EnsureComplexCollectionEntriesCapacity( + complexProperty, currentCollection?.Count ?? 0, originalCollection?.Count ?? 0, trim: true); if (changesFound) { - entry.SetPropertyModified(complexProperty, true); + entry.SetPropertyModified(complexProperty); } return changesFound; diff --git a/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs b/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs index 072f817e3e3..23988df8884 100644 --- a/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// diff --git a/src/EFCore/ChangeTracking/Internal/ConvertingValueComparer.cs b/src/EFCore/ChangeTracking/Internal/ConvertingValueComparer.cs index d02486cc887..be221c8a40a 100644 --- a/src/EFCore/ChangeTracking/Internal/ConvertingValueComparer.cs +++ b/src/EFCore/ChangeTracking/Internal/ConvertingValueComparer.cs @@ -1,10 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +using static System.Linq.Expressions.Expression; -using System.Diagnostics.CodeAnalysis; -using static Expression; +namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// /// A composable value comparer that accepts a value comparer, and exposes it as a value comparer for a base type. @@ -17,7 +16,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public class ConvertingValueComparer - <[DynamicallyAccessedMembers( +<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] TTo, TFrom> : ValueComparer, IInfrastructure diff --git a/src/EFCore/ChangeTracking/Internal/DependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/DependentKeyValueFactory.cs index 412b640544b..bd1379d562a 100644 --- a/src/EFCore/ChangeTracking/Internal/DependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/DependentKeyValueFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// diff --git a/src/EFCore/ChangeTracking/Internal/DependentsMap.cs b/src/EFCore/ChangeTracking/Internal/DependentsMap.cs index 42f6d6027a9..ae891a0f204 100644 --- a/src/EFCore/ChangeTracking/Internal/DependentsMap.cs +++ b/src/EFCore/ChangeTracking/Internal/DependentsMap.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// diff --git a/src/EFCore/ChangeTracking/Internal/EntityReferenceMap.cs b/src/EFCore/ChangeTracking/Internal/EntityReferenceMap.cs index 26905ffd1c7..9e0264e594c 100644 --- a/src/EFCore/ChangeTracking/Internal/EntityReferenceMap.cs +++ b/src/EFCore/ChangeTracking/Internal/EntityReferenceMap.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// @@ -250,7 +248,7 @@ var numberOfStates case 1 when returnDeleted: return _deletedReferenceMap!.Values; case 0: - return Enumerable.Empty(); + return []; } } diff --git a/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs b/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs index 0c1d989c68d..bae89bf32a6 100644 --- a/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs +++ b/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; @@ -155,7 +154,8 @@ private void SetValuesFromDto(InternalEntryBase entry, IRuntimeTypeBase structur var item = dtoList[i]; if (item != null) { - SetValuesFromDto(GetComplexCollectionEntry(entry, complexProperty, i), (IRuntimeComplexType)complexProperty.ComplexType, item); + SetValuesFromDto( + GetComplexCollectionEntry(entry, complexProperty, i), (IRuntimeComplexType)complexProperty.ComplexType, item); } } } @@ -219,7 +219,8 @@ private void SetValuesFromDto(InternalEntryBase entry, IRuntimeTypeBase structur continue; } - var nestedCollection = (IList)((IRuntimePropertyBase)nestedComplexProperty).GetIndexedCollectionAccessor().Create(nestedList.Count); + var nestedCollection = (IList)((IRuntimePropertyBase)nestedComplexProperty).GetIndexedCollectionAccessor() + .Create(nestedList.Count); for (var i = 0; i < nestedList.Count; i++) { var nestedDtoItem = nestedList[i]; @@ -229,7 +230,8 @@ private void SetValuesFromDto(InternalEntryBase entry, IRuntimeTypeBase structur } else { - var nestedComplexObject = CreateComplexObjectFromDto((IRuntimeComplexType)nestedComplexProperty.ComplexType, nestedDtoItem); + var nestedComplexObject = CreateComplexObjectFromDto( + (IRuntimeComplexType)nestedComplexProperty.ComplexType, nestedDtoItem); nestedCollection.Add(nestedComplexObject); } } @@ -314,11 +316,14 @@ public override void SetValues(PropertyValues propertyValues) } } - /// + /// public override void SetValues(IDictionary values) => SetValuesFromDictionary(InternalEntry, (IRuntimeTypeBase)StructuralType, Check.NotNull(values)); - private void SetValuesFromDictionary(InternalEntryBase entry, IRuntimeTypeBase structuralType, IDictionary values) + private void SetValuesFromDictionary( + InternalEntryBase entry, + IRuntimeTypeBase structuralType, + IDictionary values) { foreach (var property in structuralType.GetProperties()) { @@ -341,13 +346,15 @@ private void SetValuesFromDictionary(InternalEntryBase entry, IRuntim if (complexValue != null && dictionaryList == null) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionValueNotDictionaryList(complexProperty.Name, complexValue.GetType().ShortDisplayName())); + CoreStrings.ComplexCollectionValueNotDictionaryList( + complexProperty.Name, complexValue.GetType().ShortDisplayName())); } IList? complexList = null; if (dictionaryList != null) { - complexList = (IList)((IRuntimePropertyBase)complexProperty).GetIndexedCollectionAccessor().Create(dictionaryList.Count); + complexList = (IList)((IRuntimePropertyBase)complexProperty).GetIndexedCollectionAccessor() + .Create(dictionaryList.Count); for (var i = 0; i < dictionaryList.Count; i++) { var item = dictionaryList[i]; @@ -355,8 +362,10 @@ private void SetValuesFromDictionary(InternalEntryBase entry, IRuntim if (item != null && itemDict == null) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionValueNotDictionaryList(complexProperty.Name, item.GetType().ShortDisplayName())); + CoreStrings.ComplexCollectionValueNotDictionaryList( + complexProperty.Name, item.GetType().ShortDisplayName())); } + complexList.Add(CreateComplexObjectFromDictionary((IRuntimeComplexType)complexProperty.ComplexType, itemDict)); } } @@ -416,12 +425,12 @@ public override object? this[string propertyName] { get { - if (StructuralType.FindProperty(propertyName) is IProperty property) + if (StructuralType.FindProperty(propertyName) is { } property) { return GetValueInternal(InternalEntry, property); } - if (StructuralType.FindComplexProperty(propertyName) is IComplexProperty complexProperty) + if (StructuralType.FindComplexProperty(propertyName) is { } complexProperty) { return GetValueInternal(InternalEntry, complexProperty); } @@ -431,13 +440,13 @@ public override object? this[string propertyName] } set { - if (StructuralType.FindProperty(propertyName) is IProperty property) + if (StructuralType.FindProperty(propertyName) is { } property) { SetValueInternal(InternalEntry, property, value); return; } - if (StructuralType.FindComplexProperty(propertyName) is IComplexProperty complexProperty) + if (StructuralType.FindComplexProperty(propertyName) is { } complexProperty) { SetValueInternal(InternalEntry, complexProperty, value); return; @@ -491,7 +500,9 @@ public override IList? this[IComplexProperty complexProperty] /// /// Creates a complex object from a dictionary of property values using EF's property accessors. /// - private object? CreateComplexObjectFromDictionary(IRuntimeComplexType complexType, IDictionary? dictionary) + private object? CreateComplexObjectFromDictionary( + IRuntimeComplexType complexType, + IDictionary? dictionary) { if (dictionary == null) { @@ -522,20 +533,22 @@ public override IList? this[IComplexProperty complexProperty] { if (nestedComplexProperty.IsCollection && nestedValue is IList nestedList) { - var nestedCollection = (IList)((IRuntimePropertyBase)nestedComplexProperty).GetIndexedCollectionAccessor().Create(nestedList.Count); + var nestedCollection = (IList)((IRuntimePropertyBase)nestedComplexProperty).GetIndexedCollectionAccessor() + .Create(nestedList.Count); foreach (var nestedItem in nestedList) { - nestedCollection.Add(nestedItem switch - { - null => null, - IDictionary nestedItemDict - => CreateComplexObjectFromDictionary( - (IRuntimeComplexType)nestedComplexProperty.ComplexType, nestedItemDict), - _ => throw new InvalidOperationException( - CoreStrings.ComplexCollectionValueNotDictionaryList( - nestedComplexProperty.Name, nestedList.GetType().ShortDisplayName())) - }); + nestedCollection.Add( + nestedItem switch + { + null => null, + IDictionary nestedItemDict + => CreateComplexObjectFromDictionary( + (IRuntimeComplexType)nestedComplexProperty.ComplexType, nestedItemDict), + _ => throw new InvalidOperationException( + CoreStrings.ComplexCollectionValueNotDictionaryList( + nestedComplexProperty.Name, nestedList.GetType().ShortDisplayName())) + }); } var propertyInfo = nestedComplexProperty.PropertyInfo; @@ -547,19 +560,22 @@ IDictionary nestedItemDict else if (nestedComplexProperty.IsCollection && nestedValue != null) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionValueNotDictionaryList(nestedComplexProperty.Name, nestedValue.GetType().ShortDisplayName())); + CoreStrings.ComplexCollectionValueNotDictionaryList( + nestedComplexProperty.Name, nestedValue.GetType().ShortDisplayName())); } else if (!nestedComplexProperty.IsCollection) { object? nestedComplexObject = null; if (nestedValue is IDictionary nestedDict) { - nestedComplexObject = CreateComplexObjectFromDictionary((IRuntimeComplexType)nestedComplexProperty.ComplexType, nestedDict); + nestedComplexObject = CreateComplexObjectFromDictionary( + (IRuntimeComplexType)nestedComplexProperty.ComplexType, nestedDict); } else if (nestedValue != null) { throw new InvalidOperationException( - CoreStrings.ComplexPropertyValueNotDictionary(nestedComplexProperty.Name, nestedValue.GetType().ShortDisplayName())); + CoreStrings.ComplexPropertyValueNotDictionary( + nestedComplexProperty.Name, nestedValue.GetType().ShortDisplayName())); } var propertyInfo = nestedComplexProperty.PropertyInfo; diff --git a/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs b/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs index a6c24262cb9..357d258e532 100644 --- a/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs @@ -67,7 +67,8 @@ public interface IInternalEntry /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public object Entity => EntityEntry.Entity; + public object Entity + => EntityEntry.Entity; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -331,7 +332,12 @@ public interface IInternalEntry /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - void SetProperty(IPropertyBase propertyBase, object? value, bool isMaterialization, bool setModified = true, bool isCascadeDelete = false); + void SetProperty( + IPropertyBase propertyBase, + object? value, + bool isMaterialization, + bool setModified = true, + bool isCascadeDelete = false); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -339,7 +345,12 @@ public interface IInternalEntry /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - void SetPropertyModified(IProperty property, bool changeState = true, bool isModified = true, bool isConceptualNull = false, bool acceptChanges = false); + void SetPropertyModified( + IProperty property, + bool changeState = true, + bool isModified = true, + bool isConceptualNull = false, + bool acceptChanges = false); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/ChangeTracking/Internal/InternalComplexEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalComplexEntry.cs index 5b8be17c366..66a06c7a841 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalComplexEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalComplexEntry.cs @@ -14,9 +14,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// public sealed class InternalComplexEntry : InternalEntryBase { - private int _ordinal; - private int _originalOrdinal; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -32,7 +29,7 @@ public InternalComplexEntry( Check.DebugAssert(complexType.ComplexProperty.IsCollection, $"{complexType} expected to be a collection"); ContainingEntry = containingEntry; - _ordinal = ordinal; + Ordinal = ordinal; OriginalOrdinal = ordinal; } @@ -64,7 +61,8 @@ public override InternalEntityEntry EntityEntry /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public IComplexProperty ComplexProperty => ComplexType.ComplexProperty; + public IComplexProperty ComplexProperty + => ComplexType.ComplexProperty; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -72,7 +70,8 @@ public override InternalEntityEntry EntityEntry /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override IStateManager StateManager => ContainingEntry.StateManager; + public override IStateManager StateManager + => ContainingEntry.StateManager; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -98,20 +97,21 @@ public override IReadOnlyList GetOrdinals() public int Ordinal { // -1 is used to indicate that the entry is deleted - get => _ordinal; + get; set { if (EntityState is not EntityState.Detached and not EntityState.Deleted - && _ordinal != value + && field != value && ContainingEntry.GetComplexCollectionEntry(ComplexProperty, value) is var existingEntry && existingEntry != this && existingEntry is { EntityState: not EntityState.Detached and not EntityState.Deleted, Ordinal: not -1 }) { - throw new InvalidOperationException(CoreStrings.ComplexCollectionEntryOrdinalReadOnly( - ComplexProperty.DeclaringType.ShortNameChain(), ComplexProperty.Name)); + throw new InvalidOperationException( + CoreStrings.ComplexCollectionEntryOrdinalReadOnly( + ComplexProperty.DeclaringType.ShortNameChain(), ComplexProperty.Name)); } - _ordinal = value; + field = value; } } @@ -121,7 +121,8 @@ public int Ordinal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public IRuntimeComplexType ComplexType => (IRuntimeComplexType)StructuralType; + public IRuntimeComplexType ComplexType + => (IRuntimeComplexType)StructuralType; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -132,20 +133,21 @@ public int Ordinal public int OriginalOrdinal { // -1 is used to indicate that the entry is added - get => _originalOrdinal; + get; set { if (EntityState is not EntityState.Detached and not EntityState.Added - && _originalOrdinal != value + && field != value && ContainingEntry.GetComplexCollectionOriginalEntry(ComplexProperty, value) is var existingEntry && existingEntry != this && existingEntry is { EntityState: not EntityState.Detached and not EntityState.Added, OriginalOrdinal: not -1 }) { - throw new InvalidOperationException(CoreStrings.ComplexCollectionEntryOriginalOrdinalReadOnly( - ComplexProperty.DeclaringType.ShortNameChain(), ComplexProperty.Name)); + throw new InvalidOperationException( + CoreStrings.ComplexCollectionEntryOriginalOrdinalReadOnly( + ComplexProperty.DeclaringType.ShortNameChain(), ComplexProperty.Name)); } - _originalOrdinal = value; + field = value; } } @@ -157,8 +159,8 @@ public int OriginalOrdinal /// public override object? ReadPropertyValue(IPropertyBase propertyBase) => EntityState == EntityState.Deleted - ? GetOriginalValue(propertyBase) - : base.ReadPropertyValue(propertyBase); + ? GetOriginalValue(propertyBase) + : base.ReadPropertyValue(propertyBase); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -168,8 +170,8 @@ public int OriginalOrdinal /// public override T ReadOriginalValue(IProperty property, int originalValueIndex) => EntityState == EntityState.Added - ? GetCurrentValue(property) - : base.ReadOriginalValue(property, originalValueIndex); + ? GetCurrentValue(property) + : base.ReadOriginalValue(property, originalValueIndex); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -179,8 +181,8 @@ public override T ReadOriginalValue(IProperty property, int originalValueInde /// public override object? GetOriginalValue(IPropertyBase propertyBase) => EntityState == EntityState.Added - ? GetCurrentValue(propertyBase) - : base.GetOriginalValue(propertyBase); + ? GetCurrentValue(propertyBase) + : base.GetOriginalValue(propertyBase); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -301,7 +303,7 @@ public string GetPropertyPath(bool withElement = true) } private static string GetShortNameChain(IReadOnlyTypeBase structuralType) - => (structuralType is IReadOnlyComplexType complexType) && (complexType.ComplexProperty is IReadOnlyComplexProperty complexProperty) + => (structuralType is IReadOnlyComplexType { ComplexProperty: var complexProperty }) ? complexProperty.IsCollection ? "" : GetShortNameChain(complexProperty.DeclaringType) + "." + complexProperty.Name + "." @@ -327,13 +329,11 @@ public DebugView DebugView () => ToDebugString(ChangeTrackerDebugStringOptions.ShortDefault), () => ToDebugString()); - private string ToDebugString( ChangeTrackerDebugStringOptions options = ChangeTrackerDebugStringOptions.LongDefault, int indent = 0) { var builder = new StringBuilder(); - var indentString = new string(' ', indent); try { diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs index 411e875575a..9af4a68e45a 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs @@ -3,7 +3,6 @@ using System.Collections.Specialized; using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -106,7 +105,8 @@ public InternalEntityEntry( /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public IRuntimeEntityType EntityType => (IRuntimeEntityType)StructuralType; + public IRuntimeEntityType EntityType + => (IRuntimeEntityType)StructuralType; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -467,7 +467,6 @@ public void PropagateValue( } } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -489,7 +488,7 @@ public override void AcceptChanges() } private static readonly MethodInfo ReadRelationshipSnapshotValueMethod - = typeof(InternalEntityEntry).GetMethod(nameof(InternalEntityEntry.ReadRelationshipSnapshotValue))!; + = typeof(InternalEntityEntry).GetMethod(nameof(ReadRelationshipSnapshotValue))!; [UnconditionalSuppressMessage( "ReflectionAnalysis", "IL2060", @@ -525,7 +524,6 @@ public TProperty GetRelationshipSnapshotValue(IPropertyBase propertyB public object? GetRelationshipSnapshotValue(IPropertyBase propertyBase) => _relationshipsSnapshot.GetValue(this, propertyBase); - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -678,7 +676,6 @@ protected override void OnPropertyChanged(IPropertyBase propertyBase, object? va base.OnPropertyChanged(propertyBase, value, setModified); } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -765,10 +762,9 @@ public override void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool fo } else { - var property = EntityType.GetFlattenedProperties().FirstOrDefault( - p => (EntityState != EntityState.Modified - || IsModified(p)) - && PropertyStateData.IsPropertyFlagged(p.GetIndex(), PropertyFlag.Null)); + var property = EntityType.GetFlattenedProperties().FirstOrDefault(p => (EntityState != EntityState.Modified + || IsModified(p)) + && PropertyStateData.IsPropertyFlagged(p.GetIndex(), PropertyFlag.Null)); if (property != null) { @@ -778,7 +774,7 @@ public override void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool fo CoreStrings.PropertyConceptualNullSensitive( property.Name, EntityType.DisplayName(), - this.BuildOriginalValuesString(new[] { property }))); + this.BuildOriginalValuesString([property]))); } throw new InvalidOperationException( @@ -964,13 +960,13 @@ public void HandleINotifyCollectionChanged( this, navigation, eventArgs.NewItems!.OfType(), - Enumerable.Empty()); + []); break; case NotifyCollectionChangedAction.Remove: StateManager.InternalEntityEntryNotifier.NavigationCollectionChanged( this, navigation, - Enumerable.Empty(), + [], eventArgs.OldItems!.OfType()); break; case NotifyCollectionChangedAction.Replace: diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntryBase.InternalComplexCollectionEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntryBase.InternalComplexCollectionEntry.cs index 7ad99221396..93f2cb812fe 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntryBase.InternalComplexCollectionEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntryBase.InternalComplexCollectionEntry.cs @@ -123,24 +123,22 @@ private struct InternalComplexCollectionEntry(InternalEntryBase entry, IComplexP return _originalEntries; } - else + + _entries ??= new List(capacity); + for (var i = _entries.Count; i < capacity; i++) { - _entries ??= new List(capacity); - for (var i = _entries.Count; i < capacity; i++) - { - _entries.Add(null); - } + _entries.Add(null); + } - if (trim) + if (trim) + { + for (var i = _entries.Count - 1; i >= capacity; i--) { - for (var i = _entries.Count - 1; i >= capacity; i--) - { - _entries.RemoveAt(i); - } + _entries.RemoveAt(i); } - - return _entries; } + + return _entries; } public void AcceptChanges() @@ -157,6 +155,7 @@ public void AcceptChanges() { continue; } + entry.AcceptChanges(); // The entry was deleted, so AcceptChanges removed it from the list i--; @@ -171,6 +170,7 @@ public void AcceptChanges() { _originalEntries.Add(_entries[i]); } + for (var i = 0; i < _originalEntries.Count; i++) { _originalEntries[i]?.AcceptChanges(); @@ -204,10 +204,12 @@ public void RejectChanges() { _entries ??= new List(_originalEntries.Count); _entries.Clear(); + // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < _originalEntries.Count; i++) { _entries.Add(_originalEntries[i]); } + foreach (var entry in _entries) { entry?.Ordinal = entry.OriginalOrdinal; @@ -226,13 +228,15 @@ public InternalComplexEntry GetEntry(int ordinal, bool original = false) if (_containingEntry.EntityState == EntityState.Added) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionOriginalEntryAddedEntity(ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); + CoreStrings.ComplexCollectionOriginalEntryAddedEntity( + ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); } if (_containingEntry.GetOriginalValue(_complexCollection) == null) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionEntryOriginalNull(_complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); + CoreStrings.ComplexCollectionEntryOriginalNull( + _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); } } else @@ -240,24 +244,27 @@ public InternalComplexEntry GetEntry(int ordinal, bool original = false) if (_containingEntry.EntityState == EntityState.Deleted) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionEntryDeletedEntity(ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); + CoreStrings.ComplexCollectionEntryDeletedEntity( + ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); } if (_containingEntry[_complexCollection] == null) { throw new InvalidOperationException( - CoreStrings.ComplexCollectionNotInitialized(_complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); + CoreStrings.ComplexCollectionNotInitialized( + _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name)); } } var entries = GetOrCreateEntries(original); if (ordinal < 0 || ordinal >= entries.Count) { - throw new InvalidOperationException(original - ? CoreStrings.ComplexCollectionEntryOriginalOrdinalInvalid( - ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name, entries.Count) - : CoreStrings.ComplexCollectionEntryOrdinalInvalid( - ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name, entries.Count)); + throw new InvalidOperationException( + original + ? CoreStrings.ComplexCollectionEntryOriginalOrdinalInvalid( + ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name, entries.Count) + : CoreStrings.ComplexCollectionEntryOrdinalInvalid( + ordinal, _complexCollection.DeclaringType.ShortNameChain(), _complexCollection.Name, entries.Count)); } var complexEntry = entries[ordinal]; @@ -279,9 +286,12 @@ public readonly void MoveEntry(int fromOrdinal, int toOrdinal, bool original = f } var entries = original ? _originalEntries : _entries; - Check.DebugAssert(entries != null, $"Property {_complexCollection.Name} should have{(original ? " original" : "")} entries initialized."); - if (fromOrdinal < 0 || fromOrdinal >= entries.Count - || toOrdinal < 0 || toOrdinal >= entries.Count) + Check.DebugAssert( + entries != null, $"Property {_complexCollection.Name} should have{(original ? " original" : "")} entries initialized."); + if (fromOrdinal < 0 + || fromOrdinal >= entries.Count + || toOrdinal < 0 + || toOrdinal >= entries.Count) { throw new ArgumentOutOfRangeException( CoreStrings.ComplexCollectionMoveInvalidOrdinals(fromOrdinal, toOrdinal, entries.Count)); @@ -350,9 +360,11 @@ public void SetState(EntityState oldState, EntityState newState, bool acceptChan setOriginalState = true; } - EnsureCapacity(((IList?)_containingEntry.GetOriginalValue(_complexCollection))?.Count ?? 0, + EnsureCapacity( + ((IList?)_containingEntry.GetOriginalValue(_complexCollection))?.Count ?? 0, original: true, trim: false); - EnsureCapacity(((IList?)_containingEntry[_complexCollection])?.Count ?? 0, + EnsureCapacity( + ((IList?)_containingEntry[_complexCollection])?.Count ?? 0, original: false, trim: false); var defaultState = newState == EntityState.Modified && !modifyProperties @@ -397,11 +409,14 @@ public readonly int ValidateOrdinal(InternalComplexEntry entry, bool original, L if (ordinal < 0 || ordinal >= entries.Count) { var property = entry.ComplexProperty; - throw new InvalidOperationException(original - ? CoreStrings.ComplexCollectionEntryOriginalOrdinalInvalid( - ordinal, property.ComplexType.ShortNameChain(), property.Name, ((IList?)_containingEntry.GetOriginalValue(_complexCollection))?.Count ?? 0) - : CoreStrings.ComplexCollectionEntryOrdinalInvalid( - ordinal, property.ComplexType.ShortNameChain(), property.Name, ((IList?)_containingEntry.GetCurrentValue(_complexCollection))?.Count ?? 0)); + throw new InvalidOperationException( + original + ? CoreStrings.ComplexCollectionEntryOriginalOrdinalInvalid( + ordinal, property.ComplexType.ShortNameChain(), property.Name, + ((IList?)_containingEntry.GetOriginalValue(_complexCollection))?.Count ?? 0) + : CoreStrings.ComplexCollectionEntryOrdinalInvalid( + ordinal, property.ComplexType.ShortNameChain(), property.Name, + ((IList?)_containingEntry.GetCurrentValue(_complexCollection))?.Count ?? 0)); } return ordinal; @@ -439,7 +454,7 @@ public void HandleStateChange(InternalComplexEntry entry, EntityState oldState, } } else if (oldState == EntityState.Added - && newState is not EntityState.Detached) + && newState is not EntityState.Detached) { InsertEntry(entry, original: true); } @@ -465,6 +480,7 @@ public void HandleStateChange(InternalComplexEntry entry, EntityState oldState, { _containingEntry.SetPropertyModified(property, false); } + break; case EntityState.Deleted: if (oldState is not EntityState.Detached @@ -472,8 +488,9 @@ public void HandleStateChange(InternalComplexEntry entry, EntityState oldState, { RemoveEntry(entry, original: false); } + entry.Ordinal = -1; - _containingEntry.SetPropertyModified(property, true); + _containingEntry.SetPropertyModified(property); break; case EntityState.Added: if (oldState is not EntityState.Detached @@ -481,18 +498,22 @@ public void HandleStateChange(InternalComplexEntry entry, EntityState oldState, { RemoveEntry(entry, original: true); } + entry.OriginalOrdinal = -1; - _containingEntry.SetPropertyModified(property, true); + _containingEntry.SetPropertyModified(property); break; case EntityState.Modified: - _containingEntry.SetPropertyModified(property, true); + _containingEntry.SetPropertyModified(property); break; case EntityState.Unchanged: - if (GetOrCreateEntries(original: false).All(e => e == null || (e.EntityState == EntityState.Unchanged && e.Ordinal == e.OriginalOrdinal)) - && GetOrCreateEntries(original: true).All(e => e == null || (e.EntityState == EntityState.Unchanged && e.Ordinal == e.OriginalOrdinal))) + if (GetOrCreateEntries(original: false).All(e + => e == null || (e.EntityState == EntityState.Unchanged && e.Ordinal == e.OriginalOrdinal)) + && GetOrCreateEntries(original: true).All(e + => e == null || (e.EntityState == EntityState.Unchanged && e.Ordinal == e.OriginalOrdinal))) { _containingEntry.SetPropertyModified(property, false); } + break; } @@ -502,18 +523,23 @@ public void HandleStateChange(InternalComplexEntry entry, EntityState oldState, if (newState is not EntityState.Detached and not EntityState.Deleted) { var currentOrdinal = entry.Ordinal; - Check.DebugAssert(currentOrdinal >= 0 && currentOrdinal < currentEntries.Count, - $"ComplexEntry ordinal {currentOrdinal} is invalid for property {property.Name}."); - Check.DebugAssert(currentEntries[currentOrdinal] == entry, $"ComplexEntry at ordinal {currentOrdinal} does not match the provided entry for property {property.Name}."); + Check.DebugAssert( + currentOrdinal >= 0 && currentOrdinal < currentEntries.Count, + $"ComplexEntry ordinal {currentOrdinal} is invalid for property {property.Name}."); + Check.DebugAssert( + currentEntries[currentOrdinal] == entry, + $"ComplexEntry at ordinal {currentOrdinal} does not match the provided entry for property {property.Name}."); } var originalEntries = GetOrCreateEntries(original: true); if (newState is not EntityState.Detached and not EntityState.Added) { var originalOrdinal = entry.OriginalOrdinal; - Check.DebugAssert(originalOrdinal >= 0 && originalOrdinal < originalEntries.Count, + Check.DebugAssert( + originalOrdinal >= 0 && originalOrdinal < originalEntries.Count, $"ComplexEntry original ordinal {originalOrdinal} is invalid for property {property.Name}."); - Check.DebugAssert(originalEntries[originalOrdinal] == entry, + Check.DebugAssert( + originalEntries[originalOrdinal] == entry, $"ComplexEntry at OriginalOrdinal {originalOrdinal} does not match the provided entry for property {property.Name}."); } } @@ -627,7 +653,7 @@ public readonly void InsertEntry(InternalComplexEntry entry, bool original = fal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public readonly override string ToString() + public override readonly string ToString() => ToDebugString(ChangeTrackerDebugStringOptions.ShortDefault); /// @@ -636,14 +662,15 @@ public readonly override string ToString() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + // ReSharper disable once UnusedMember.Local public readonly DebugView DebugView { get { var instance = this; return new DebugView( - () => instance.ToDebugString(ChangeTrackerDebugStringOptions.ShortDefault), - () => instance.ToDebugString()); + () => instance.ToDebugString(ChangeTrackerDebugStringOptions.ShortDefault), + () => instance.ToDebugString()); } } diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntryBase.StateData.cs b/src/EFCore/ChangeTracking/Internal/InternalEntryBase.StateData.cs index ff811f16e9f..1a1eed21824 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntryBase.StateData.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntryBase.StateData.cs @@ -44,6 +44,7 @@ protected internal enum PropertyFlag /// doing so can result in application failures when updating to a new Entity Framework Core release. /// IsLoaded = 3, + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -51,6 +52,7 @@ protected internal enum PropertyFlag /// doing so can result in application failures when updating to a new Entity Framework Core release. /// IsTemporary = 4, + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntryBase.cs b/src/EFCore/ChangeTracking/Internal/InternalEntryBase.cs index d81686ad029..ac2b693833e 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntryBase.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntryBase.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -107,7 +106,8 @@ public DbContext Context /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual InternalEntryBase ContainingEntry => this; + public virtual InternalEntryBase ContainingEntry + => this; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -115,7 +115,8 @@ public DbContext Context /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual InternalEntityEntry EntityEntry => (InternalEntityEntry)this; + public virtual InternalEntityEntry EntityEntry + => (InternalEntityEntry)this; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -140,7 +141,8 @@ public virtual EntityState EntityState /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual IReadOnlyList GetOrdinals() => []; + public virtual IReadOnlyList GetOrdinals() + => []; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -148,7 +150,8 @@ public virtual EntityState EntityState /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - protected virtual ref StateData PropertyStateData => ref _stateData; + protected virtual ref StateData PropertyStateData + => ref _stateData; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -364,7 +367,8 @@ public virtual void MarkUnchangedFromQuery() { if (complexCollection.IsCollection) { - _complexCollectionEntries[complexCollection.GetIndex()].SetState(EntityState.Detached, EntityState.Unchanged, acceptChanges: false, modifyProperties: false); + _complexCollectionEntries[complexCollection.GetIndex()].SetState( + EntityState.Detached, EntityState.Unchanged, acceptChanges: false, modifyProperties: false); } } } @@ -511,7 +515,8 @@ public void SetPropertyModified( && changeState && !isModified && !_stateData.AnyPropertiesFlagged(PropertyFlag.Modified) - && StructuralType.GetFlattenedComplexProperties().All(p => !p.IsCollection || !_complexCollectionEntries[p.GetIndex()].IsModified())) + && StructuralType.GetFlattenedComplexProperties() + .All(p => !p.IsCollection || !_complexCollectionEntries[p.GetIndex()].IsModified())) { OnStateChanging(EntityState.Unchanged); _stateData.EntityState = EntityState.Unchanged; @@ -532,7 +537,7 @@ public bool IsModified(IComplexProperty property) return property.IsCollection ? _complexCollectionEntries[property.GetIndex()].IsModified() : property.ComplexType.GetFlattenedProperties().Any(IsModified) - || property.ComplexType.GetFlattenedComplexProperties().Any(cp => cp.IsCollection && IsModified(cp)); + || property.ComplexType.GetFlattenedComplexProperties().Any(cp => cp.IsCollection && IsModified(cp)); } /// @@ -596,7 +601,8 @@ public virtual void OnComplexPropertyModified(IComplexProperty property, bool is else if (currentState == EntityState.Modified && !isModified && !_stateData.AnyPropertiesFlagged(PropertyFlag.Modified) - && StructuralType.GetFlattenedComplexProperties().All(p => !p.IsCollection || !_complexCollectionEntries[p.GetIndex()].IsModified())) + && StructuralType.GetFlattenedComplexProperties() + .All(p => !p.IsCollection || !_complexCollectionEntries[p.GetIndex()].IsModified())) { OnStateChanging(EntityState.Unchanged); _stateData.EntityState = EntityState.Unchanged; @@ -650,10 +656,10 @@ protected virtual CurrentValueType GetValueType(IProperty property) StructuralType.CheckContains(property); return _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsStoreGenerated) - ? CurrentValueType.StoreGenerated - : _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsTemporary) - ? CurrentValueType.Temporary - : CurrentValueType.Normal; + ? CurrentValueType.StoreGenerated + : _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsTemporary) + ? CurrentValueType.Temporary + : CurrentValueType.Normal; } /// @@ -898,8 +904,8 @@ private void WritePropertyValue( /// public object? GetCurrentValue(IPropertyBase propertyBase) => StructuralType.CheckContains(propertyBase) is not IProperty property || !IsConceptualNull(property) - ? this[propertyBase] - : null; + ? this[propertyBase] + : null; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -909,8 +915,8 @@ private void WritePropertyValue( /// public object? GetPreStoreGeneratedCurrentValue(IPropertyBase propertyBase) => StructuralType.CheckContains(propertyBase) is not IProperty property || !IsConceptualNull(property) - ? ReadPropertyValue(propertyBase) - : null; + ? ReadPropertyValue(propertyBase) + : null; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -968,7 +974,7 @@ public void SetOriginalValue( } } else if (isComplexCollection - && EntityState is EntityState.Unchanged or EntityState.Modified) + && EntityState is EntityState.Unchanged or EntityState.Modified) { ((StateManager as StateManager)?.ChangeDetector as ChangeDetector)?.DetectComplexCollectionChanges(this, complexProperty!); } @@ -1008,7 +1014,8 @@ private void ReorderOriginalComplexCollectionEntries(IComplexProperty complexPro for (; newOrdinal < newOriginalCollection.Count; newOrdinal++) { var element = newOriginalCollection[newOrdinal]; - if (element != null && elementToOriginalEntry.TryGetValue(element, out var originalEntry) + if (element != null + && elementToOriginalEntry.TryGetValue(element, out var originalEntry) && originalEntry.OriginalOrdinal != newOrdinal) { if (originalEntry.EntityState is EntityState.Detached or EntityState.Added) @@ -1109,7 +1116,7 @@ public InternalComplexEntry GetComplexCollectionEntry(IComplexProperty property, StructuralType.CheckContains(property); Check.DebugAssert(property.IsCollection, $"Property {property.Name} should be a collection"); - return _complexCollectionEntries[property.GetIndex()].GetOrCreateEntries(original: false)!; + return _complexCollectionEntries[property.GetIndex()].GetOrCreateEntries(original: false); } /// @@ -1137,7 +1144,7 @@ public InternalComplexEntry GetComplexCollectionOriginalEntry(IComplexProperty p StructuralType.CheckContains(property); Check.DebugAssert(property.IsCollection, $"Property {property.Name} should be a collection"); - return _complexCollectionEntries[property.GetIndex()].GetOrCreateEntries(original: true)!; + return _complexCollectionEntries[property.GetIndex()].GetOrCreateEntries(original: true); } /// @@ -1155,7 +1162,11 @@ public IEnumerable GetFlattenedComplexEntries() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual void EnsureComplexCollectionEntriesCapacity(IComplexProperty property, int capacity, int originalCapacity, bool trim = true) + public virtual void EnsureComplexCollectionEntriesCapacity( + IComplexProperty property, + int capacity, + int originalCapacity, + bool trim = true) { StructuralType.CheckContains(property); Check.DebugAssert(property.IsCollection, $"Property {property.Name} should be a collection"); @@ -1319,9 +1330,9 @@ private void SetProperty( if (asProperty != null && valueType == CurrentValueType.Normal && (!asProperty.ClrType.IsNullableType() - || asProperty.GetContainingForeignKeys().Any( - fk => fk is { IsRequired: true, DeleteBehavior: DeleteBehavior.Cascade or DeleteBehavior.ClientCascade } - && fk.DeclaringEntityType.IsAssignableFrom(StructuralType)))) + || asProperty.GetContainingForeignKeys().Any(fk + => fk is { IsRequired: true, DeleteBehavior: DeleteBehavior.Cascade or DeleteBehavior.ClientCascade } + && fk.DeclaringEntityType.IsAssignableFrom(StructuralType)))) { if (value == null) { @@ -1695,8 +1706,8 @@ public bool HasExplicitValue(IProperty property) StructuralType.CheckContains(property); return !HasSentinelValue(property) - || _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsStoreGenerated) - || _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsTemporary); + || _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsStoreGenerated) + || _stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.IsTemporary); } private bool HasSentinelValue(IProperty property) @@ -1704,8 +1715,8 @@ private bool HasSentinelValue(IProperty property) StructuralType.CheckContains(property); return property.IsShadowProperty() - ? AreEqual(_shadowValues[property.GetShadowIndex()], property.Sentinel, property) - : property.GetGetter().HasSentinelValueUsingContainingEntity(EntityEntry.Entity); + ? AreEqual(_shadowValues[property.GetShadowIndex()], property.Sentinel, property) + : property.GetGetter().HasSentinelValueUsingContainingEntity(EntityEntry.Entity); } /// @@ -1717,7 +1728,8 @@ private bool HasSentinelValue(IProperty property) public bool HasStoreGeneratedValue(IProperty property) => GetValueType(property) == CurrentValueType.StoreGenerated; - IInternalEntry IInternalEntry.ContainingEntry => ContainingEntry; + IInternalEntry IInternalEntry.ContainingEntry + => ContainingEntry; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs index e5e1ebac0ef..1a7342cd017 100644 --- a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs +++ b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs @@ -208,9 +208,8 @@ public virtual void NavigationReferenceChanged( // Clear the inverse reference, unless it has already been changed if (inverse != null && ReferenceEquals(oldTargetEntry[inverse], entry.Entity) - && (entry.EntityType.GetNavigations().All( - n => n == navigation - || !ReferenceEquals(oldTargetEntry.Entity, entry[n])))) + && (entry.EntityType.GetNavigations().All(n => n == navigation + || !ReferenceEquals(oldTargetEntry.Entity, entry[n])))) { SetNavigation(oldTargetEntry, inverse, null, fromQuery: false); } @@ -1204,15 +1203,14 @@ bool TryFind( IForeignKey secondForeignKey, out InternalEntityEntry? joinEntry) { - var key = joinEntityType.FindKey(new[] { firstForeignKey.Properties[0], secondForeignKey.Properties[0] }); + var key = joinEntityType.FindKey([firstForeignKey.Properties[0], secondForeignKey.Properties[0]]); if (key != null) { joinEntry = entry.StateManager.TryGetEntry( key, - new[] - { + [ firstEntry[firstForeignKey.PrincipalKey.Properties[0]], secondEntry[secondForeignKey.PrincipalKey.Properties[0]] - }); + ]); return true; } diff --git a/src/EFCore/ChangeTracking/Internal/NullableValueComparer`.cs b/src/EFCore/ChangeTracking/Internal/NullableValueComparer`.cs index eaaefe13a1a..4050d775f62 100644 --- a/src/EFCore/ChangeTracking/Internal/NullableValueComparer`.cs +++ b/src/EFCore/ChangeTracking/Internal/NullableValueComparer`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// @@ -12,7 +10,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public class NullableValueComparer - <[DynamicallyAccessedMembers( +<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] T> : ValueComparer, IInfrastructure diff --git a/src/EFCore/ChangeTracking/Internal/OriginalPropertyValues.cs b/src/EFCore/ChangeTracking/Internal/OriginalPropertyValues.cs index 47793412cfd..6b4165b4ac9 100644 --- a/src/EFCore/ChangeTracking/Internal/OriginalPropertyValues.cs +++ b/src/EFCore/ChangeTracking/Internal/OriginalPropertyValues.cs @@ -71,7 +71,8 @@ protected override void SetValueInternal(IInternalEntry entry, IPropertyBase pro // The stored original collection might contain references to the current elements, // so we need to recreate it using stored values. - var clonedCollection = (IList)((IRuntimePropertyBase)complexProperty).GetIndexedCollectionAccessor().Create(originalCollection.Count); + var clonedCollection = (IList)((IRuntimePropertyBase)complexProperty).GetIndexedCollectionAccessor() + .Create(originalCollection.Count); for (var i = 0; i < originalCollection.Count; i++) { clonedCollection.Add( diff --git a/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs index ebb618df0c6..ac83bf4545c 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; diff --git a/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs index 472c5283e04..c45d4865c80 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; diff --git a/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs index 67942dc3ad1..2e4c114edf3 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; diff --git a/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs index 1757474eb0c..f39e2d5747a 100644 --- a/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; diff --git a/src/EFCore/ChangeTracking/Internal/Snapshot.cs b/src/EFCore/ChangeTracking/Internal/Snapshot.cs index 460dfc5c6e0..7b2fc0ae283 100644 --- a/src/EFCore/ChangeTracking/Internal/Snapshot.cs +++ b/src/EFCore/ChangeTracking/Internal/Snapshot.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// diff --git a/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs index f4bb13c6d81..28d31f20e7e 100644 --- a/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs @@ -57,7 +57,9 @@ public virtual Expression CreateConstructorExpression( var index = GetPropertyIndex(propertyBase); if (index >= 0) { - Check.DebugAssert(propertyBases[index] == null, $"Both {propertyBase.Name} and {propertyBases[index]?.Name} have the same index {index}."); + Check.DebugAssert( + propertyBases[index] == null, + $"Both {propertyBase.Name} and {propertyBases[index]?.Name} have the same index {index}."); types[index] = (propertyBase as IProperty)?.ClrType ?? typeof(object); propertyBases[index] = propertyBase; @@ -65,7 +67,8 @@ public virtual Expression CreateConstructorExpression( } } - Check.DebugAssert(actualCount == count, + Check.DebugAssert( + actualCount == count, $"Count of snapshottable properties {actualCount} for {structuralType.DisplayName()} does not match expected count {count}."); Expression constructorExpression; @@ -117,7 +120,8 @@ protected virtual Expression CreateSnapshotExpression( ? null : Expression.Variable(clrType, "structuralType"); - Check.DebugAssert(structuralTypeVariable != null || count == 0, + Check.DebugAssert( + structuralTypeVariable != null || count == 0, "If there are any properties then the entity parameter must be used"); var indicesExpression = parameter == null || !parameter.Type.IsAssignableTo(typeof(IInternalEntry)) ? (Expression)Expression.Property(null, typeof(ReadOnlySpan), nameof(ReadOnlySpan<>.Empty)) @@ -204,7 +208,6 @@ private Expression CreateSnapshotValueExpression(Expression expression, IPropert ? Expression.Call( null, SnapshotComplexCollectionMethod, - expression.Type.IsAssignableTo(typeof(IList)) ? expression : Expression.Convert(expression, typeof(IList)), @@ -216,10 +219,11 @@ private Expression CreateSnapshotValueExpression(Expression expression, IPropert ? expression : Expression.Convert(expression, typeof(IEnumerable))); } + return expression; } - if (GetValueComparer(property) is not ValueComparer comparer) + if (GetValueComparer(property) is not { } comparer) { return expression; } @@ -339,11 +343,13 @@ private static readonly MethodInfo SnapshotCollectionMethod { return null; } + var snapshot = new HashSet(ReferenceEqualityComparer.Instance); foreach (var item in collection) { snapshot.Add(item); } + return snapshot; } @@ -369,6 +375,7 @@ private static readonly MethodInfo SnapshotComplexCollectionMethod // We need to preserve the original reference, these are only used to find moved items, not modified properties on them snapshot.Add(item); } + return snapshot; } } diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs index 5527fc6e1e0..51ca099f032 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs @@ -935,7 +935,7 @@ public virtual IEnumerable> GetRecor return danglers; } - return Enumerable.Empty>(); + return []; } /// @@ -1042,7 +1042,7 @@ public virtual IEnumerable GetDependents( var dependentIdentityMap = FindIdentityMap(foreignKey.DeclaringEntityType.FindPrimaryKey()); return dependentIdentityMap != null && foreignKey.PrincipalEntityType.IsAssignableFrom(principalEntry.EntityType) ? dependentIdentityMap.GetDependentsMap(foreignKey).GetDependents(principalEntry) - : Enumerable.Empty(); + : []; } /// @@ -1055,7 +1055,7 @@ public virtual IEnumerable GetEntries(IKey key) { var identityMap = FindIdentityMap(key); return identityMap == null - ? Enumerable.Empty() + ? [] : identityMap.All(); } @@ -1087,7 +1087,7 @@ public virtual IEnumerable GetDependentsUsingRelationshipSnapshot( var dependentIdentityMap = FindIdentityMap(foreignKey.DeclaringEntityType.FindPrimaryKey()); return dependentIdentityMap != null ? dependentIdentityMap.GetDependentsMap(foreignKey).GetDependentsUsingRelationshipSnapshot(principalEntry) - : Enumerable.Empty(); + : []; } /// @@ -1110,7 +1110,7 @@ public virtual IEnumerable GetDependentsUsingRelationshipSnapshot( var navigationValue = ((InternalEntityEntry)principalEntry)[navigation]; if (navigationValue == null) { - return Enumerable.Empty(); + return []; } if (foreignKey.IsUnique) diff --git a/src/EFCore/ChangeTracking/Internal/TemporaryValuesFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/TemporaryValuesFactoryFactory.cs index 459a815fc28..c9204c2d8e8 100644 --- a/src/EFCore/ChangeTracking/Internal/TemporaryValuesFactoryFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/TemporaryValuesFactoryFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// diff --git a/src/EFCore/ChangeTracking/ListOfReferenceTypesComparer.cs b/src/EFCore/ChangeTracking/ListOfReferenceTypesComparer.cs index 5bf444702eb..33da583f6bc 100644 --- a/src/EFCore/ChangeTracking/ListOfReferenceTypesComparer.cs +++ b/src/EFCore/ChangeTracking/ListOfReferenceTypesComparer.cs @@ -30,7 +30,8 @@ public sealed class ListOfReferenceTypesComparer : Valu && typeof(TConcreteList).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>)); private static readonly MethodInfo CompareMethod = typeof(ListOfReferenceTypesComparer).GetMethod( - nameof(Compare), BindingFlags.Static | BindingFlags.NonPublic, [typeof(object), typeof(object), typeof(Func)])!; + nameof(Compare), BindingFlags.Static | BindingFlags.NonPublic, + [typeof(object), typeof(object), typeof(Func)])!; private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfReferenceTypesComparer).GetMethod( nameof(GetHashCode), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable), typeof(Func)])!; diff --git a/src/EFCore/ChangeTracking/LocalView.cs b/src/EFCore/ChangeTracking/LocalView.cs index 661c0ccd06d..24e6d6691d5 100644 --- a/src/EFCore/ChangeTracking/LocalView.cs +++ b/src/EFCore/ChangeTracking/LocalView.cs @@ -5,7 +5,6 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -61,7 +60,6 @@ public class LocalView<[DynamicallyAccessedMembers(IEntityType.DynamicallyAccess private readonly DbContext _context; private readonly IEntityType _entityType; private int _countChanges; - private IEntityFinder? _finder; private int? _count; private bool _triggeringStateManagerChange; private bool _triggeringObservableChange; @@ -176,7 +174,7 @@ private void ObservableCollectionChanged(object? _, NotifyCollectionChangedEvent } /// - /// Returns an for all tracked entities of type + /// Returns an for all tracked entities of type /// that are not marked as deleted. /// /// An enumerator for the collection. @@ -184,7 +182,7 @@ public virtual IEnumerator GetEnumerator() => _context.GetDependencies().StateManager.GetNonDeletedEntities().GetEnumerator(); /// - /// Returns an for all tracked entities of type + /// Returns an for all tracked entities of type /// that are not marked as deleted. /// /// An enumerator for the collection. @@ -237,7 +235,7 @@ public virtual void Add(TEntity item) } /// - /// Marks all entities of type being tracked by the + /// Marks all entities of type being tracked by the /// as . /// /// @@ -280,7 +278,7 @@ public virtual bool Contains(TEntity item) } /// - /// Copies to an array all entities of type that are being tracked and are + /// Copies to an array all entities of type that are being tracked and are /// not marked as Deleted. /// /// @@ -382,7 +380,7 @@ private void StateManagerChangedHandler(InternalEntityEntry entry, EntityState p } /// - /// The number of entities of type that are being tracked and are not marked + /// The number of entities of type that are being tracked and are not marked /// as Deleted. /// /// @@ -856,6 +854,7 @@ private IProperty FindAndValidateProperty(string propertyName) return property; } + [field: AllowNull, MaybeNull] private IEntityFinder Finder - => _finder ??= (IEntityFinder)_context.GetDependencies().EntityFinderFactory.Create(_entityType); + => field ??= (IEntityFinder)_context.GetDependencies().EntityFinderFactory.Create(_entityType); } diff --git a/src/EFCore/ChangeTracking/NavigationEntry.cs b/src/EFCore/ChangeTracking/NavigationEntry.cs index fc849fac92a..46fb8ef8e46 100644 --- a/src/EFCore/ChangeTracking/NavigationEntry.cs +++ b/src/EFCore/ChangeTracking/NavigationEntry.cs @@ -69,7 +69,8 @@ protected NavigationEntry(InternalEntityEntry internalEntry, INavigationBase nav /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - protected virtual InternalEntityEntry InternalEntityEntry => (InternalEntityEntry)InternalEntry; + protected virtual InternalEntityEntry InternalEntityEntry + => (InternalEntityEntry)InternalEntry; private static INavigationBase GetNavigation(InternalEntityEntry internalEntry, string name) { diff --git a/src/EFCore/ChangeTracking/PropertyValues.cs b/src/EFCore/ChangeTracking/PropertyValues.cs index 15480976553..79a53634f9c 100644 --- a/src/EFCore/ChangeTracking/PropertyValues.cs +++ b/src/EFCore/ChangeTracking/PropertyValues.cs @@ -26,7 +26,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; /// public abstract class PropertyValues { - private IReadOnlyList? _complexCollectionProperties; + private readonly IReadOnlyList _complexCollectionProperties; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -36,7 +36,13 @@ public abstract class PropertyValues /// [EntityFrameworkInternal] protected PropertyValues(InternalEntryBase internalEntry) - => InternalEntry = internalEntry; + { + InternalEntry = internalEntry; + _complexCollectionProperties = [.. internalEntry.StructuralType.GetFlattenedComplexProperties().Where(p => p.IsCollection)]; + Check.DebugAssert( + _complexCollectionProperties.Select((p, i) => p.GetIndex() == i).All(e => e), + "Complex collection properties indices are not sequential."); + } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -145,17 +151,7 @@ public virtual IReadOnlyList Properties public virtual IReadOnlyList ComplexCollectionProperties { [DebuggerStepThrough] - get - { - if (_complexCollectionProperties == null) - { - _complexCollectionProperties = [.. StructuralType.GetFlattenedComplexProperties().Where(p => p.IsCollection)]; - Check.DebugAssert( - _complexCollectionProperties.Select((p, i) => p.GetIndex() == i).All(e => e), - "Complex collection properties indices are not sequential."); - } - return _complexCollectionProperties; - } + get => _complexCollectionProperties; } /// diff --git a/src/EFCore/ChangeTracking/ReferenceEntry.cs b/src/EFCore/ChangeTracking/ReferenceEntry.cs index 276628ed3b5..06f1886fc1d 100644 --- a/src/EFCore/ChangeTracking/ReferenceEntry.cs +++ b/src/EFCore/ChangeTracking/ReferenceEntry.cs @@ -23,8 +23,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; /// public class ReferenceEntry : NavigationEntry { - private IEntityFinder? _finder; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -270,6 +268,7 @@ public virtual EntityEntry? TargetEntry ? null : InternalEntry.StateManager.GetOrCreateEntry(CurrentValue, Metadata.TargetEntityType); + [field: AllowNull, MaybeNull] private IEntityFinder TargetFinder - => _finder ??= InternalEntry.StateManager.CreateEntityFinder(Metadata.TargetEntityType); + => field ??= InternalEntry.StateManager.CreateEntityFinder(Metadata.TargetEntityType); } diff --git a/src/EFCore/ChangeTracking/ValueComparer.cs b/src/EFCore/ChangeTracking/ValueComparer.cs index 34696dbd2bc..06423fbf54f 100644 --- a/src/EFCore/ChangeTracking/ValueComparer.cs +++ b/src/EFCore/ChangeTracking/ValueComparer.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore.ChangeTracking; @@ -41,7 +40,10 @@ internal static readonly MethodInfo EqualityComparerEqualsMethod internal static readonly MethodInfo ObjectGetHashCodeMethod = typeof(object).GetRuntimeMethod(nameof(object.GetHashCode), Type.EmptyTypes)!; - private static readonly ConcurrentDictionary _genericSnapshotMethodMap = new(); + internal static readonly PropertyInfo StructuralComparisonsStructuralEqualityComparerProperty = + typeof(StructuralComparisons).GetProperty(nameof(StructuralComparisons.StructuralEqualityComparer))!; + + private static readonly ConcurrentDictionary GenericSnapshotMethodMap = new(); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -51,13 +53,13 @@ internal static readonly MethodInfo ObjectGetHashCodeMethod /// [EntityFrameworkInternal] public static MethodInfo GetGenericSnapshotMethod(Type type) - => _genericSnapshotMethodMap.GetOrAdd( + => GenericSnapshotMethodMap.GetOrAdd( type, t => typeof(ValueComparer<>).MakeGenericType(t).GetGenericMethod( - nameof(ValueComparer.Snapshot), + nameof(ValueComparer<>.Snapshot), genericParameterCount: 0, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, - (a, b) => new[] { a[0] }, + (a, b) => [a[0]], @override: false)!); /// @@ -78,7 +80,7 @@ protected static readonly MethodInfo HashCodeAddMethod /// [EntityFrameworkInternal] protected static readonly MethodInfo ToHashCodeMethod - = typeof(HashCode).GetRuntimeMethod(nameof(HashCode.ToHashCode), new Type[0])!; + = typeof(HashCode).GetRuntimeMethod(nameof(HashCode.ToHashCode), [])!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -195,7 +197,7 @@ public virtual Expression ExtractEqualsBody( var original2 = EqualsExpression.Parameters[1]; return new ReplacingExpressionVisitor( - new Expression[] { original1, original2 }, new[] { leftExpression, rightExpression }) + [original1, original2], [leftExpression, rightExpression]) .Visit(EqualsExpression.Body); } @@ -279,7 +281,7 @@ public static ValueComparer CreateDefault( /// The type. /// The . public static ValueComparer CreateDefault - <[DynamicallyAccessedMembers( + <[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] T>(bool favorStructuralComparisons) @@ -317,7 +319,7 @@ public static ValueComparer CreateDefault // PublicMethods is required to preserve e.g. GetHashCode internal class DefaultValueComparer - <[DynamicallyAccessedMembers( + <[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] T> : ValueComparer diff --git a/src/EFCore/ChangeTracking/ValueComparer`.cs b/src/EFCore/ChangeTracking/ValueComparer`.cs index 13d56a1b8e3..7631f074234 100644 --- a/src/EFCore/ChangeTracking/ValueComparer`.cs +++ b/src/EFCore/ChangeTracking/ValueComparer`.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using ExpressionExtensions = Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions; using static System.Linq.Expressions.Expression; @@ -29,7 +28,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking; /// The type. // PublicMethods is required to preserve e.g. GetHashCode public class ValueComparer - <[DynamicallyAccessedMembers( +<[DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicProperties)] T> : ValueComparer, IEqualityComparer @@ -37,10 +36,6 @@ public class ValueComparer private Func? _equals; private Func? _hashCode; private Func? _snapshot; - private LambdaExpression? _objectEqualsExpression; - - private static readonly PropertyInfo StructuralComparisonsStructuralEqualityComparerProperty = - typeof(StructuralComparisons).GetProperty(nameof(StructuralComparisons.StructuralEqualityComparer))!; /// /// Creates a new with a default comparison @@ -129,12 +124,11 @@ public ValueComparer( param1, param2); } - var typedEquals = type.GetRuntimeMethods().FirstOrDefault( - m => m.ReturnType == typeof(bool) - && !m.IsStatic - && nameof(object.Equals).Equals(m.Name, StringComparison.Ordinal) - && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(T)); + var typedEquals = type.GetRuntimeMethods().FirstOrDefault(m => m.ReturnType == typeof(bool) + && !m.IsStatic + && nameof(object.Equals).Equals(m.Name, StringComparison.Ordinal) + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(T)); if (typedEquals != null) { @@ -157,13 +151,12 @@ public ValueComparer( && type != null) { var declaredMethods = type.GetTypeInfo().DeclaredMethods; - typedEquals = declaredMethods.FirstOrDefault( - m => m.IsStatic - && m.ReturnType == typeof(bool) - && "op_Equality".Equals(m.Name, StringComparison.Ordinal) - && m.GetParameters().Length == 2 - && m.GetParameters()[0].ParameterType == typeof(T) - && m.GetParameters()[1].ParameterType == typeof(T)); + typedEquals = declaredMethods.FirstOrDefault(m => m.IsStatic + && m.ReturnType == typeof(bool) + && "op_Equality".Equals(m.Name, StringComparison.Ordinal) + && m.GetParameters().Length == 2 + && m.GetParameters()[0].ParameterType == typeof(T) + && m.GetParameters()[1].ParameterType == typeof(T)); type = type.BaseType; } @@ -252,11 +245,12 @@ public override bool Equals(object? left, object? right) } /// + [field: AllowNull, MaybeNull] public override LambdaExpression ObjectEqualsExpression { get { - if (_objectEqualsExpression == null) + if (field == null) { var left = Parameter(typeof(object), "left"); var right = Parameter(typeof(object), "right"); @@ -266,7 +260,7 @@ public override LambdaExpression ObjectEqualsExpression [Convert(left, typeof(T)), Convert(right, typeof(T))], EqualsExpression.Body); - _objectEqualsExpression = Lambda>( + field = Lambda>( Condition( Equal(left, Constant(null)), Equal(right, Constant(null)), @@ -277,7 +271,7 @@ public override LambdaExpression ObjectEqualsExpression right); } - return _objectEqualsExpression; + return field; } } diff --git a/src/EFCore/DbContext.cs b/src/EFCore/DbContext.cs index 4e5ce4e2d39..e2464d9da1b 100644 --- a/src/EFCore/DbContext.cs +++ b/src/EFCore/DbContext.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -80,11 +79,10 @@ public class DbContext : /// for more information and examples. /// [RequiresUnreferencedCode( - "EF Core isn't fully compatible with trimming, and running the application may generate unexpected runtime failures. " - + "Some specific coding pattern are usually required to make trimming work properly, see https://aka.ms/efcore-docs-trimming for " - + "more details.")] - [RequiresDynamicCode( - "EF Core isn't fully compatible with NativeAOT, and running the application may generate unexpected runtime failures.")] + "EF Core isn't fully compatible with trimming, and running the application may generate unexpected runtime failures. " + + "Some specific coding pattern are usually required to make trimming work properly, see https://aka.ms/efcore-docs-trimming for " + + "more details."), RequiresDynamicCode( + "EF Core isn't fully compatible with NativeAOT, and running the application may generate unexpected runtime failures.")] protected DbContext() : this(new DbContextOptions()) { @@ -101,11 +99,10 @@ protected DbContext() /// /// The options for this context. [RequiresUnreferencedCode( - "EF Core isn't fully compatible with trimming, and running the application may generate unexpected runtime failures. " - + "Some specific coding pattern are usually required to make trimming work properly, see https://aka.ms/efcore-docs-trimming for " - + "more details.")] - [RequiresDynamicCode( - "EF Core isn't fully compatible with NativeAOT, and running the application may generate unexpected runtime failures.")] + "EF Core isn't fully compatible with trimming, and running the application may generate unexpected runtime failures. " + + "Some specific coding pattern are usually required to make trimming work properly, see https://aka.ms/efcore-docs-trimming for " + + "more details."), RequiresDynamicCode( + "EF Core isn't fully compatible with NativeAOT, and running the application may generate unexpected runtime failures.")] public DbContext(DbContextOptions options) { Check.NotNull(options); diff --git a/src/EFCore/DbContextOptions.cs b/src/EFCore/DbContextOptions.cs index 13839281a16..90b347ef80d 100644 --- a/src/EFCore/DbContextOptions.cs +++ b/src/EFCore/DbContextOptions.cs @@ -136,9 +136,8 @@ public override bool Equals(object? obj) protected virtual bool Equals(DbContextOptions other) => _extensionsMap.Count == other._extensionsMap.Count && _extensionsMap.Zip(other._extensionsMap) - .All( - p => p.First.Value.Ordinal == p.Second.Value.Ordinal - && p.First.Value.Extension.Info.ShouldUseSameServiceProvider(p.Second.Value.Extension.Info)); + .All(p => p.First.Value.Ordinal == p.Second.Value.Ordinal + && p.First.Value.Extension.Info.ShouldUseSameServiceProvider(p.Second.Value.Extension.Info)); /// public override int GetHashCode() diff --git a/src/EFCore/DbSet.cs b/src/EFCore/DbSet.cs index 10f4dcc0e1f..7a89377df71 100644 --- a/src/EFCore/DbSet.cs +++ b/src/EFCore/DbSet.cs @@ -3,7 +3,6 @@ using System.Collections; using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore; diff --git a/src/EFCore/Design/Internal/CSharpRuntimeAnnotationCodeGenerator.cs b/src/EFCore/Design/Internal/CSharpRuntimeAnnotationCodeGenerator.cs index ee574cc4aaa..89c3546a52b 100644 --- a/src/EFCore/Design/Internal/CSharpRuntimeAnnotationCodeGenerator.cs +++ b/src/EFCore/Design/Internal/CSharpRuntimeAnnotationCodeGenerator.cs @@ -374,7 +374,7 @@ public static void Create( { var mainBuilder = parameters.MainBuilder; var constructor = converter.GetType().GetDeclaredConstructor([typeof(JsonValueReaderWriter)]); - var jsonReaderWriterProperty = converter.GetType().GetProperty(nameof(CollectionToJsonStringConverter.JsonReaderWriter)); + var jsonReaderWriterProperty = converter.GetType().GetProperty(nameof(CollectionToJsonStringConverter<>.JsonReaderWriter)); if (constructor == null || jsonReaderWriterProperty == null) { @@ -455,7 +455,7 @@ public static void Create( .Any(t => t == typeof(ValueComparer) || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ValueComparer<>))); if (!containsNestedComparerCtor - || comparer is not IInfrastructure { Instance: ValueComparer underlyingValueComparer }) + || comparer is not IInfrastructure { Instance: { } underlyingValueComparer }) { AddNamespace(typeof(ValueComparer<>), parameters.Namespaces); AddNamespace(comparer.Type, parameters.Namespaces); diff --git a/src/EFCore/Design/MethodCallCodeFragment.cs b/src/EFCore/Design/MethodCallCodeFragment.cs index 97a9fc8f615..c8e68ae3e0a 100644 --- a/src/EFCore/Design/MethodCallCodeFragment.cs +++ b/src/EFCore/Design/MethodCallCodeFragment.cs @@ -98,7 +98,7 @@ private MethodCallCodeFragment( public virtual string Method { get; } IEnumerable IMethodCallCodeFragment.TypeArguments - => Enumerable.Empty(); + => []; /// /// Gets the method call's arguments. diff --git a/src/EFCore/Diagnostics/ConcurrencyExceptionEventData.cs b/src/EFCore/Diagnostics/ConcurrencyExceptionEventData.cs index ca051e929e4..d4feb4f2266 100644 --- a/src/EFCore/Diagnostics/ConcurrencyExceptionEventData.cs +++ b/src/EFCore/Diagnostics/ConcurrencyExceptionEventData.cs @@ -14,7 +14,6 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics; public class ConcurrencyExceptionEventData : DbContextErrorEventData { private readonly IReadOnlyList _internalEntries; - private IReadOnlyList? _entries; /// /// Constructs the event payload. @@ -42,6 +41,7 @@ public ConcurrencyExceptionEventData( /// /// The entries that were involved in the concurrency violation. /// + [field: AllowNull, MaybeNull] public virtual IReadOnlyList Entries - => _entries ??= _internalEntries.Select(e => new EntityEntry((InternalEntityEntry)e)).ToList(); + => field ??= _internalEntries.Select(e => new EntityEntry((InternalEntityEntry)e)).ToList(); } diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index 9fb70ad7d5d..5054434a5ba 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -1603,9 +1603,9 @@ private static string AccidentalComplexPropertyCollection(EventDefinitionBase de var d = (EventDefinition)definition; var p = (ComplexPropertyEventData)payload; return d.GenerateMessage( - p.Property.DeclaringType.DisplayName(), - p.Property.Name, - p.Property.ClrType.ShortDisplayName()); + p.Property.DeclaringType.DisplayName(), + p.Property.Name, + p.Property.ClrType.ShortDisplayName()); } /// @@ -1784,8 +1784,8 @@ public static void MultiplePrimaryKeyCandidates( var eventData = new TwoPropertyBaseCollectionsEventData( definition, MultiplePrimaryKeyCandidates, - new[] { firstProperty }, - new[] { secondProperty }); + [firstProperty], + [secondProperty]); diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } @@ -1816,6 +1816,7 @@ public static void MultipleNavigationProperties( { var definition = CoreResources.LogMultipleNavigationProperties(diagnostics); + // ReSharper disable PossibleMultipleEnumeration if (diagnostics.ShouldLog(definition)) { definition.Log( @@ -1836,6 +1837,7 @@ public static void MultipleNavigationProperties( diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } + // ReSharper restore PossibleMultipleEnumeration } private static string MultipleNavigationProperties(EventDefinitionBase definition, EventData payload) @@ -1878,7 +1880,7 @@ public static void MultipleInversePropertiesSameTargetWarning( definition, MultipleInversePropertiesSameTargetWarning, conflictingNavigations, - new[] { new Tuple(inverseNavigation, targetType) }); + [new Tuple(inverseNavigation, targetType)]); diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } @@ -1929,12 +1931,11 @@ public static void NonOwnershipInverseNavigationWarning( var eventData = new TwoUnmappedPropertyCollectionsEventData( definition, NonOwnershipInverseNavigationWarning, - new[] { new Tuple(navigation, declaringType.ClrType) }, - new[] - { + [new Tuple(navigation, declaringType.ClrType)], + [ new Tuple(inverseNavigation, targetType.ClrType), new Tuple(ownershipNavigation, targetType.ClrType) - }); + ]); diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } @@ -1989,18 +1990,16 @@ public static void ForeignKeyAttributesOnBothPropertiesWarning( var eventData = new TwoUnmappedPropertyCollectionsEventData( definition, ForeignKeyAttributesOnBothPropertiesWarning, - new[] - { + [ new Tuple( firstNavigation.GetIdentifyingMemberInfo()!, firstNavigation.DeclaringEntityType.ClrType), new Tuple(firstProperty, firstNavigation.DeclaringEntityType.ClrType) - }, - new[] - { + ], + [ new Tuple( secondNavigation.GetIdentifyingMemberInfo()!, secondNavigation.DeclaringEntityType.ClrType), new Tuple(secondProperty, secondNavigation.DeclaringEntityType.ClrType) - }); + ]); diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } @@ -2051,8 +2050,8 @@ public static void ForeignKeyAttributesOnBothNavigationsWarning( var eventData = new TwoPropertyBaseCollectionsEventData( definition, ForeignKeyAttributesOnBothNavigationsWarning, - new[] { firstNavigation }, - new[] { secondNavigation }); + [firstNavigation], + [secondNavigation]); diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } @@ -2099,8 +2098,8 @@ public static void ConflictingForeignKeyAttributesOnNavigationAndPropertyWarning var eventData = new TwoUnmappedPropertyCollectionsEventData( definition, ConflictingForeignKeyAttributesOnNavigationAndPropertyWarning, - new[] { new Tuple(navigation.GetIdentifyingMemberInfo()!, navigation.DeclaringEntityType.ClrType) }, - new[] { new Tuple(property, property.DeclaringType!) }); + [new Tuple(navigation.GetIdentifyingMemberInfo()!, navigation.DeclaringEntityType.ClrType)], + [new Tuple(property, property.DeclaringType!)]); diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } @@ -2359,7 +2358,8 @@ public static void ComplexElementPropertyChangeDetectedSensitive( property.Name, oldValue, newValue, - internalComplexEntry.EntityEntry.BuildCurrentValuesString(property.DeclaringType.ContainingEntityType.FindPrimaryKey()!.Properties)); + internalComplexEntry.EntityEntry.BuildCurrentValuesString( + property.DeclaringType.ContainingEntityType.FindPrimaryKey()!.Properties)); } if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) @@ -3071,7 +3071,7 @@ private static string ValueGenerated(EventDefinitionBase definition, EventData p /// The internal entity entry. /// The property. /// The value generated. - /// Indicates whether or not the value is a temporary or permanent value. + /// Indicates whether the value is a temporary or permanent value. public static void ValueGeneratedSensitive( this IDiagnosticsLogger diagnostics, InternalEntityEntry internalEntityEntry, diff --git a/src/EFCore/Diagnostics/EventDefinitionBase.cs b/src/EFCore/Diagnostics/EventDefinitionBase.cs index f3d9f50f17f..d1d2bdb466b 100644 --- a/src/EFCore/Diagnostics/EventDefinitionBase.cs +++ b/src/EFCore/Diagnostics/EventDefinitionBase.cs @@ -31,7 +31,6 @@ protected EventDefinitionBase( EventIdCode = eventIdCode; var warningsConfiguration = loggingOptions.WarningsConfiguration; - if (warningsConfiguration != null) { var levelOverride = warningsConfiguration.GetLevel(eventId); @@ -86,12 +85,11 @@ protected virtual Exception WarningAsError(string message) internal sealed class MessageExtractingLogger : ILogger { - private string? _message; - + [field: AllowNull, MaybeNull] public string Message { - get => _message ?? throw new InvalidOperationException(); - private set => _message = value; + get => field ?? throw new InvalidOperationException(); + private set; } void ILogger.Log( diff --git a/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs b/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs index e8d363fcea2..b0c22a35178 100644 --- a/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs +++ b/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs @@ -17,8 +17,7 @@ public readonly struct IdentityResolutionInterceptionData /// Constructs the parameter object. /// /// The in use. - [EntityFrameworkInternal] - [UsedImplicitly] + [EntityFrameworkInternal, UsedImplicitly] public IdentityResolutionInterceptionData(DbContext context) => Context = context; diff --git a/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs b/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs index 19800577210..2a9044badcc 100644 --- a/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs +++ b/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs @@ -17,8 +17,7 @@ public readonly struct InstantiationBindingInterceptionData /// Constructs the parameter object. /// /// The entity type for which the binding is being used. - [EntityFrameworkInternal] - [UsedImplicitly] + [EntityFrameworkInternal, UsedImplicitly] public InstantiationBindingInterceptionData(ITypeBase typeBase) => TypeBase = typeBase; diff --git a/src/EFCore/Diagnostics/InterceptionResult`.cs b/src/EFCore/Diagnostics/InterceptionResult`.cs index 21eef6a7694..a404dd317ba 100644 --- a/src/EFCore/Diagnostics/InterceptionResult`.cs +++ b/src/EFCore/Diagnostics/InterceptionResult`.cs @@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics; /// /// A value of this type is passed to all interceptor methods that are called before the operation /// being intercepted is executed. -/// Typically the interceptor should return the value passed in. +/// Typically, the interceptor should return the value passed in. /// However, creating a result with causes the operation being /// intercepted to be suppressed; that is, the operation is not executed. /// The value in the result is then used as a substitute return value for the operation that was suppressed. @@ -23,8 +23,6 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics; /// The new result to use. public readonly struct InterceptionResult { - private readonly TResult _result; - /// /// Creates a new instance indicating that /// execution should be suppressed and the given result should be used instead. @@ -35,7 +33,7 @@ public static InterceptionResult SuppressWithResult(TResult result) private InterceptionResult(TResult result) { - _result = result; + Result = result; HasResult = true; } @@ -56,7 +54,7 @@ public TResult Result throw new InvalidOperationException(CoreStrings.NoInterceptionResult); } - return _result; + return field; } } diff --git a/src/EFCore/Diagnostics/Internal/DiagnosticsLogger.cs b/src/EFCore/Diagnostics/Internal/DiagnosticsLogger.cs index babebe150d7..c4b59bea939 100644 --- a/src/EFCore/Diagnostics/Internal/DiagnosticsLogger.cs +++ b/src/EFCore/Diagnostics/Internal/DiagnosticsLogger.cs @@ -121,7 +121,7 @@ protected void DispatchEventData( => ((IDiagnosticsLogger)this).DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); /// - /// Checks whether or not the message should be sent to the . + /// Checks whether the message should be sent to the . /// /// The definition of the event to log. /// @@ -133,7 +133,7 @@ protected bool ShouldLog(EventDefinitionBase definition) => ((IDiagnosticsLogger)this).ShouldLog(definition); /// - /// Determines whether or not an instance is needed based on whether or + /// Determines whether an instance is needed based on whether or /// not there is a , an , or an enabled for /// the given event. /// diff --git a/src/EFCore/Diagnostics/Internal/Interceptors.cs b/src/EFCore/Diagnostics/Internal/Interceptors.cs index 9047238e651..bfdef244fe6 100644 --- a/src/EFCore/Diagnostics/Internal/Interceptors.cs +++ b/src/EFCore/Diagnostics/Internal/Interceptors.cs @@ -14,7 +14,6 @@ public class Interceptors : IInterceptors private readonly IServiceProvider _serviceProvider; private readonly IEnumerable _injectedInterceptors; private readonly Dictionary _aggregators; - private CoreOptionsExtension? _coreOptionsExtension; private List? _interceptors; /// @@ -70,7 +69,7 @@ private IReadOnlyList RegisteredInterceptors /// else is ready for them to do interception anyway. /// private CoreOptionsExtension? CoreOptionsExtension - => _coreOptionsExtension ??= _serviceProvider + => field ??= _serviceProvider .GetRequiredService() .Extensions .OfType() diff --git a/src/EFCore/Diagnostics/Internal/LoggingOptions.cs b/src/EFCore/Diagnostics/Internal/LoggingOptions.cs index 1ce5f190765..4df4a7c46fe 100644 --- a/src/EFCore/Diagnostics/Internal/LoggingOptions.cs +++ b/src/EFCore/Diagnostics/Internal/LoggingOptions.cs @@ -105,13 +105,5 @@ public virtual void Validate(IDbContextOptions options) /// public virtual bool ShouldWarnForStringEnumValueInJson(Type enumType) - { - if (_warnedForStringEnums.ContainsKey(enumType)) - { - return false; - } - - _warnedForStringEnums[enumType] = true; - return true; - } + => _warnedForStringEnums.TryAdd(enumType, true); } diff --git a/src/EFCore/Diagnostics/MaterializationInterceptionData.cs b/src/EFCore/Diagnostics/MaterializationInterceptionData.cs index 73cf44c1617..a7041a895b2 100644 --- a/src/EFCore/Diagnostics/MaterializationInterceptionData.cs +++ b/src/EFCore/Diagnostics/MaterializationInterceptionData.cs @@ -23,8 +23,7 @@ public readonly struct MaterializationInterceptionData /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [EntityFrameworkInternal] - [UsedImplicitly] + [EntityFrameworkInternal, UsedImplicitly] public MaterializationInterceptionData( MaterializationContext materializationContext, IEntityType entityType, diff --git a/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs b/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs index 8ccfa4bd4f3..a6f5e032ee2 100644 --- a/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs +++ b/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs @@ -48,16 +48,14 @@ public virtual void UpdateTrackedInstance( if (existingEntry.State == EntityState.Added) { - foreach (var propertyEntry in tempEntry.Properties.Where( - e => e.Metadata.GetBeforeSaveBehavior() != PropertySaveBehavior.Throw)) + foreach (var propertyEntry in tempEntry.Properties.Where(e => e.Metadata.GetBeforeSaveBehavior() != PropertySaveBehavior.Throw)) { existingEntry.Property(propertyEntry.Metadata.Name).CurrentValue = propertyEntry.CurrentValue; } } else { - foreach (var propertyEntry in tempEntry.Properties.Where( - e => e.Metadata.GetAfterSaveBehavior() != PropertySaveBehavior.Throw)) + foreach (var propertyEntry in tempEntry.Properties.Where(e => e.Metadata.GetAfterSaveBehavior() != PropertySaveBehavior.Throw)) { var existingPropertyEntry = existingEntry.Property(propertyEntry.Metadata.Name); diff --git a/src/EFCore/Diagnostics/WarningsConfiguration.cs b/src/EFCore/Diagnostics/WarningsConfiguration.cs index 59bf127a98e..6b1060d01ef 100644 --- a/src/EFCore/Diagnostics/WarningsConfiguration.cs +++ b/src/EFCore/Diagnostics/WarningsConfiguration.cs @@ -166,7 +166,7 @@ public virtual WarningsConfiguration WithExplicit( public virtual WarningsConfiguration TryWithExplicit(EventId eventId, WarningBehavior warningBehavior) => _explicitBehaviors.ContainsKey(eventId.Id) ? this - : WithExplicit(new[] { eventId }, warningBehavior); + : WithExplicit([eventId], warningBehavior); /// /// Returns a value indicating whether all of the options used in diff --git a/src/EFCore/EF.CompileAsyncQuery.cs b/src/EFCore/EF.CompileAsyncQuery.cs index 10f8afb663c..c08dadd0d1a 100644 --- a/src/EFCore/EF.CompileAsyncQuery.cs +++ b/src/EFCore/EF.CompileAsyncQuery.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Query.Internal; namespace Microsoft.EntityFrameworkCore; diff --git a/src/EFCore/EF.cs b/src/EFCore/EF.cs index 6a5645e1afa..72b164ada33 100644 --- a/src/EFCore/EF.cs +++ b/src/EFCore/EF.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore; /// diff --git a/src/EFCore/EFCore.csproj b/src/EFCore/EFCore.csproj index ebd55af327c..959949da569 100644 --- a/src/EFCore/EFCore.csproj +++ b/src/EFCore/EFCore.csproj @@ -22,6 +22,7 @@ Microsoft.EntityFrameworkCore.DbSet + diff --git a/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs b/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs index 1fcda68fe55..0602cf9ea5b 100644 --- a/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs +++ b/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Query.Internal; @@ -13,18 +12,17 @@ namespace Microsoft.EntityFrameworkCore; /// Entity Framework LINQ related extension methods. /// [UnconditionalSuppressMessage( - "ReflectionAnalysis", - "IL2060", - Justification = - "MakeGenericMethod is used in this class to create MethodCallExpression nodes, but only if the method in question is called " - + "from user code - so it's never trimmed. After https://github.com/dotnet/linker/issues/2482 is fixed, the suppression will no " - + "longer be necessary.")] -[UnconditionalSuppressMessage( - "AOT", - "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", - Justification = - "MakeGenericMethod is used in this class to create MethodCallExpression nodes, but only if the method in question is called " - + "from user code - so it's never trimmed.")] + "ReflectionAnalysis", + "IL2060", + Justification = + "MakeGenericMethod is used in this class to create MethodCallExpression nodes, but only if the method in question is called " + + "from user code - so it's never trimmed. After https://github.com/dotnet/linker/issues/2482 is fixed, the suppression will no " + + "longer be necessary."), UnconditionalSuppressMessage( + "AOT", + "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = + "MakeGenericMethod is used in this class to create MethodCallExpression nodes, but only if the method in question is called " + + "from user code - so it's never trimmed.")] public static class EntityFrameworkQueryableExtensions { /// @@ -2429,20 +2427,16 @@ public static async Task> ToHashSetAsync( internal static readonly MethodInfo IncludeMethodInfo = typeof(EntityFrameworkQueryableExtensions) .GetTypeInfo().GetDeclaredMethods(nameof(Include)) - .Single( - mi => - mi.GetGenericArguments().Length == 2 - && mi.GetParameters().Any( - pi => pi.Name == "navigationPropertyPath" && pi.ParameterType != typeof(string))); + .Single(mi => + mi.GetGenericArguments().Length == 2 + && mi.GetParameters().Any(pi => pi.Name == "navigationPropertyPath" && pi.ParameterType != typeof(string))); internal static readonly MethodInfo NotQuiteIncludeMethodInfo = typeof(EntityFrameworkQueryableExtensions) .GetTypeInfo().GetDeclaredMethods(nameof(NotQuiteInclude)) - .Single( - mi => - mi.GetGenericArguments().Length == 2 - && mi.GetParameters().Any( - pi => pi.Name == "navigationPropertyPath" && pi.ParameterType != typeof(string))); + .Single(mi => + mi.GetGenericArguments().Length == 2 + && mi.GetParameters().Any(pi => pi.Name == "navigationPropertyPath" && pi.ParameterType != typeof(string))); /// /// Specifies related entities to include in the query results. The navigation property to be included is specified starting with the @@ -2501,20 +2495,18 @@ internal static readonly MethodInfo ThenIncludeAfterEnumerableMethodInfo = typeof(EntityFrameworkQueryableExtensions) .GetTypeInfo().GetDeclaredMethods(nameof(ThenInclude)) .Where(mi => mi.GetGenericArguments().Length == 3) - .Single( - mi => - { - var typeInfo = mi.GetParameters()[0].ParameterType.GenericTypeArguments[1]; - return typeInfo.IsGenericType - && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); - }); + .Single(mi => + { + var typeInfo = mi.GetParameters()[0].ParameterType.GenericTypeArguments[1]; + return typeInfo.IsGenericType + && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + }); internal static readonly MethodInfo ThenIncludeAfterReferenceMethodInfo = typeof(EntityFrameworkQueryableExtensions) .GetTypeInfo().GetDeclaredMethods(nameof(ThenInclude)) - .Single( - mi => mi.GetGenericArguments().Length == 3 - && mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter); + .Single(mi => mi.GetGenericArguments().Length == 3 + && mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter); /// /// Specifies additional related data to be further included based on a related type that was just included. @@ -2599,9 +2591,7 @@ IEnumerator IEnumerable.GetEnumerator() internal static readonly MethodInfo StringIncludeMethodInfo = typeof(EntityFrameworkQueryableExtensions) .GetTypeInfo().GetDeclaredMethods(nameof(Include)) - .Single( - mi => mi.GetParameters().Any( - pi => pi.Name == "navigationPropertyPath" && pi.ParameterType == typeof(string))); + .Single(mi => mi.GetParameters().Any(pi => pi.Name == "navigationPropertyPath" && pi.ParameterType == typeof(string))); /// /// Specifies related entities to include in the query results. The navigation property to be included is @@ -2712,7 +2702,8 @@ public static IQueryable IgnoreQueryFilters( /// A new query that will not apply any model-level entity query filters. /// is . public static IQueryable IgnoreQueryFilters( - this IQueryable source, [NotParameterized] IReadOnlyCollection filterKeys) + this IQueryable source, + [NotParameterized] IReadOnlyCollection filterKeys) where TEntity : class => source.Provider is EntityQueryProvider ? source.Provider.CreateQuery( @@ -2944,8 +2935,8 @@ source.Provider is EntityQueryProvider /// public static IQueryable TagWithCallSite( this IQueryable source, - [NotParameterized] [CallerFilePath] string? filePath = null, - [NotParameterized] [CallerLineNumber] int lineNumber = 0) + [NotParameterized, CallerFilePath] string? filePath = null, + [NotParameterized, CallerLineNumber] int lineNumber = 0) => source.Provider is EntityQueryProvider ? source.Provider.CreateQuery( Expression.Call( @@ -3404,7 +3395,9 @@ public static int ExecuteUpdate( /// A collection of set property statements specifying properties to update. /// A to observe while waiting for the task to complete. /// The total number of rows updated in the database. - [DynamicDependency("ExecuteUpdate``1(System.Linq.IQueryable{``1},System.Collections.Generic.IReadOnlyList{ITuple})", typeof(EntityFrameworkQueryableExtensions))] + [DynamicDependency( + "ExecuteUpdate``1(System.Linq.IQueryable{``1},System.Collections.Generic.IReadOnlyList{ITuple})", + typeof(EntityFrameworkQueryableExtensions))] public static Task ExecuteUpdateAsync( this IQueryable source, Action> setPropertyCalls, @@ -3437,8 +3430,7 @@ private static int ExecuteUpdate(this IQueryable source, [NotP public static readonly MethodInfo ExecuteUpdateMethodInfo = typeof(EntityFrameworkQueryableExtensions) .GetMethods(BindingFlags.NonPublic | BindingFlags.Static) - .Single( - m => m.Name == nameof(ExecuteUpdate) && m.GetParameters()[1].ParameterType == typeof(IReadOnlyList)); + .Single(m => m.Name == nameof(ExecuteUpdate) && m.GetParameters()[1].ParameterType == typeof(IReadOnlyList)); #endregion } diff --git a/src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs b/src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs index 25f5b761c2f..255b01a2737 100644 --- a/src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs +++ b/src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Infrastructure.Internal; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -340,8 +339,8 @@ public static IServiceCollection AddDbContextPool serviceCollection.TryAddSingleton, DbContextPool>(); serviceCollection.TryAddScoped, ScopedDbContextLease>(); - serviceCollection.TryAddScoped( - sp => sp.GetRequiredService>().Context); + serviceCollection.TryAddScoped(sp + => sp.GetRequiredService>().Context); if (typeof(TContextService) != typeof(TContextImplementation)) { @@ -1022,8 +1021,8 @@ public static IServiceCollection AddPooledDbContextFactory AddPoolingOptions(serviceCollection, optionsAction, poolSize); serviceCollection.TryAddSingleton, DbContextPool>(); - serviceCollection.TryAddSingleton>( - sp => new PooledDbContextFactory(sp.GetRequiredService>())); + serviceCollection.TryAddSingleton>(sp + => new PooledDbContextFactory(sp.GetRequiredService>())); serviceCollection.TryAddScoped(sp => sp.GetRequiredService>().CreateDbContext()); return serviceCollection; diff --git a/src/EFCore/Extensions/Internal/ExpressionExtensions.cs b/src/EFCore/Extensions/Internal/ExpressionExtensions.cs index 4400e4b1ff7..58d4cbff5b3 100644 --- a/src/EFCore/Extensions/Internal/ExpressionExtensions.cs +++ b/src/EFCore/Extensions/Internal/ExpressionExtensions.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; + // ReSharper disable once CheckNamespace namespace Microsoft.EntityFrameworkCore.Internal; @@ -231,7 +231,7 @@ static Expression GenerateEqualExpression( IReadOnlyProperty property, int i) => property.ClrType.IsValueType - && property.ClrType.UnwrapNullableType() is Type nonNullableType + && property.ClrType.UnwrapNullableType() is var nonNullableType && !(nonNullableType == typeof(bool) || nonNullableType.IsNumeric() || nonNullableType.IsEnum) ? Infrastructure.ExpressionExtensions.CreateEqualsExpression( Expression.Call( diff --git a/src/EFCore/Extensions/Internal/TypeExtensions.cs b/src/EFCore/Extensions/Internal/TypeExtensions.cs index a867c0afef5..8fd36eaa1bb 100644 --- a/src/EFCore/Extensions/Internal/TypeExtensions.cs +++ b/src/EFCore/Extensions/Internal/TypeExtensions.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Text; // ReSharper disable once CheckNamespace @@ -65,11 +64,10 @@ public static string GenerateParameterName(this Type type) return defaultPropertyAttribute == null ? null : type.GetRuntimeProperties() - .FirstOrDefault( - pi => - pi.Name == defaultPropertyAttribute.MemberName - && pi.IsIndexerProperty() - && pi.SetMethod?.GetParameters() is { Length: 2 } parameters - && parameters[0].ParameterType == typeof(string)); + .FirstOrDefault(pi => + pi.Name == defaultPropertyAttribute.MemberName + && pi.IsIndexerProperty() + && pi.SetMethod?.GetParameters() is { Length: 2 } parameters + && parameters[0].ParameterType == typeof(string)); } } diff --git a/src/EFCore/Extensions/PropertyBaseExtensions.cs b/src/EFCore/Extensions/PropertyBaseExtensions.cs index 637fd328611..b77df736e58 100644 --- a/src/EFCore/Extensions/PropertyBaseExtensions.cs +++ b/src/EFCore/Extensions/PropertyBaseExtensions.cs @@ -21,7 +21,6 @@ public static string Format(this IEnumerable properties, => "{" + string.Join( ", ", - properties.Select( - p => "'" + p.Name + "'" + (includeTypes ? " : " + p.ClrType.DisplayName(fullName: false) : ""))) + properties.Select(p => "'" + p.Name + "'" + (includeTypes ? " : " + p.ClrType.DisplayName(fullName: false) : ""))) + "}"; } diff --git a/src/EFCore/IDbContextFactory.cs b/src/EFCore/IDbContextFactory.cs index 180d1deb2e7..dcf89959fd2 100644 --- a/src/EFCore/IDbContextFactory.cs +++ b/src/EFCore/IDbContextFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore; /// diff --git a/src/EFCore/IEntityTypeConfiguration.cs b/src/EFCore/IEntityTypeConfiguration.cs index a2368584522..833332b6c77 100644 --- a/src/EFCore/IEntityTypeConfiguration.cs +++ b/src/EFCore/IEntityTypeConfiguration.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore; /// diff --git a/src/EFCore/Infrastructure/AnnotatableBase.cs b/src/EFCore/Infrastructure/AnnotatableBase.cs index 9a061b5a684..5961fd47109 100644 --- a/src/EFCore/Infrastructure/AnnotatableBase.cs +++ b/src/EFCore/Infrastructure/AnnotatableBase.cs @@ -276,7 +276,7 @@ protected virtual Annotation CreateAnnotation(string name, object? value) /// Gets all runtime annotations on the current object. /// public virtual IEnumerable GetRuntimeAnnotations() - => _runtimeAnnotations?.OrderBy(p => p.Key).Select(p => p.Value) ?? Enumerable.Empty(); + => _runtimeAnnotations?.OrderBy(p => p.Key).Select(p => p.Value) ?? []; /// /// Adds a runtime annotation to this object. Throws if an annotation with the specified name already exists. diff --git a/src/EFCore/Infrastructure/CoreOptionsExtension.cs b/src/EFCore/Infrastructure/CoreOptionsExtension.cs index 3c87a8f759b..04ed76bbb07 100644 --- a/src/EFCore/Infrastructure/CoreOptionsExtension.cs +++ b/src/EFCore/Infrastructure/CoreOptionsExtension.cs @@ -39,7 +39,6 @@ public class CoreOptionsExtension : IDbContextOptionsExtension private int? _maxPoolSize; private TimeSpan _loggingCacheTime = DefaultLoggingCacheTime; private bool _serviceProviderCachingEnabled = true; - private DbContextOptionsExtensionInfo? _info; private IEnumerable? _interceptors; private IEnumerable? _singletonInterceptors; private Action? _seed; @@ -99,8 +98,9 @@ protected CoreOptionsExtension(CoreOptionsExtension copyFrom) /// /// Information/metadata about the extension. /// + [field: AllowNull, MaybeNull] public virtual DbContextOptionsExtensionInfo Info - => _info ??= new ExtensionInfo(this); + => field ??= new ExtensionInfo(this); /// /// Override this method in a derived class to ensure that any clone created is also of that class. @@ -662,7 +662,6 @@ public virtual void Validate(IDbContextOptions options) private sealed class ExtensionInfo(CoreOptionsExtension extension) : DbContextOptionsExtensionInfo(extension) { private int? _serviceProviderHash; - private string? _logFragment; private new CoreOptionsExtension Extension => (CoreOptionsExtension)base.Extension; @@ -670,11 +669,12 @@ private sealed class ExtensionInfo(CoreOptionsExtension extension) : DbContextOp public override bool IsDatabaseProvider => false; + [field: AllowNull, MaybeNull] public override string LogFragment { get { - if (_logFragment == null) + if (field == null) { var builder = new StringBuilder(); @@ -703,10 +703,10 @@ public override string LogFragment builder.Append("MaxPoolSize=").Append(Extension._maxPoolSize).Append(' '); } - _logFragment = builder.ToString(); + field = builder.ToString(); } - return _logFragment; + return field; } } diff --git a/src/EFCore/Infrastructure/DatabaseFacade.cs b/src/EFCore/Infrastructure/DatabaseFacade.cs index e370468294f..8d33d895c6b 100644 --- a/src/EFCore/Infrastructure/DatabaseFacade.cs +++ b/src/EFCore/Infrastructure/DatabaseFacade.cs @@ -3,7 +3,6 @@ using System.ComponentModel; using System.Data.Common; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore.Infrastructure; @@ -15,7 +14,6 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure; public class DatabaseFacade : IInfrastructure, IDatabaseFacadeDependenciesAccessor, IResettableService { private readonly DbContext _context; - private IDatabaseFacadeDependencies? _dependencies; /// /// Initializes a new instance of the class. Instances of this class are typically @@ -26,8 +24,9 @@ public class DatabaseFacade : IInfrastructure, IDatabaseFacade public DatabaseFacade(DbContext context) => _context = context; + [field: AllowNull, MaybeNull] private IDatabaseFacadeDependencies Dependencies - => _dependencies ??= _context.GetService(); + => field ??= _context.GetService(); /// /// Ensures that the database for the context exists. @@ -204,7 +203,7 @@ public virtual Task EnsureDeletedAsync(CancellationToken cancellationToken => Dependencies.DatabaseCreator.EnsureDeletedAsync(cancellationToken); /// - /// Determines whether or not the database is available and can be connected to. + /// Determines whether the database is available and can be connected to. /// /// /// @@ -227,7 +226,7 @@ public virtual bool CanConnect() => Dependencies.DatabaseCreator.CanConnect(); /// - /// Determines whether or not the database is available and can be connected to. + /// Determines whether the database is available and can be connected to. /// /// /// @@ -387,7 +386,7 @@ public virtual IDbContextTransaction? CurrentTransaction => Dependencies.TransactionManager.CurrentTransaction; /// - /// Gets or sets a value indicating whether or not a transaction will be created automatically by + /// Gets or sets a value indicating whether a transaction will be created automatically by /// if none of the 'BeginTransaction' or 'UseTransaction' methods have been called. /// /// @@ -428,7 +427,7 @@ public virtual bool AutoTransactionsEnabled } /// - /// Gets or sets a value indicating whether or not a transaction will be created automatically by + /// Gets or sets a value indicating whether a transaction will be created automatically by /// if neither 'BeginTransaction' nor 'UseTransaction' has been called. /// /// diff --git a/src/EFCore/Infrastructure/DbContextModelAttribute.cs b/src/EFCore/Infrastructure/DbContextModelAttribute.cs index b621fc4f117..bebeb262a0c 100644 --- a/src/EFCore/Infrastructure/DbContextModelAttribute.cs +++ b/src/EFCore/Infrastructure/DbContextModelAttribute.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Infrastructure; /// diff --git a/src/EFCore/Infrastructure/DbSetProperty.cs b/src/EFCore/Infrastructure/DbSetProperty.cs index 01481381ccd..590668c2c50 100644 --- a/src/EFCore/Infrastructure/DbSetProperty.cs +++ b/src/EFCore/Infrastructure/DbSetProperty.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Infrastructure; /// diff --git a/src/EFCore/Infrastructure/EntityFrameworkMetricsData.cs b/src/EFCore/Infrastructure/EntityFrameworkMetricsData.cs index 055d1a3056d..33a66eb7550 100644 --- a/src/EFCore/Infrastructure/EntityFrameworkMetricsData.cs +++ b/src/EFCore/Infrastructure/EntityFrameworkMetricsData.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Microsoft.EntityFrameworkCore.Infrastructure.Internal; diff --git a/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs b/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs index b9d52303691..5ca912c5608 100644 --- a/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs +++ b/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Infrastructure.Internal; @@ -312,9 +311,8 @@ public virtual EntityFrameworkServicesBuilder TryAddCoreServices() TryAdd(); TryAdd(); - TryAdd( - p => p.GetService()?.FindExtension()?.DbContextLogger - ?? new NullDbContextLogger()); + TryAdd(p => p.GetService()?.FindExtension()?.DbContextLogger + ?? new NullDbContextLogger()); // This has to be lazy to avoid creating instances that are not disposed ServiceCollectionMap diff --git a/src/EFCore/Infrastructure/ExpressionExtensions.cs b/src/EFCore/Infrastructure/ExpressionExtensions.cs index c65455ea345..3eed5f195a2 100644 --- a/src/EFCore/Infrastructure/ExpressionExtensions.cs +++ b/src/EFCore/Infrastructure/ExpressionExtensions.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Internal; @@ -59,9 +58,9 @@ public static MemberExpression MakeMemberAccess( /// The value that will be assigned. /// The representing the assignment binding. [UnconditionalSuppressMessage( - "ReflectionAnalysis", "IL2077", - Justification = "AssignBinaryExpression is preserved via DynamicDependency below")] - [DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Linq.Expressions.AssignBinaryExpression", "System.Linq.Expressions")] + "ReflectionAnalysis", "IL2077", + Justification = "AssignBinaryExpression is preserved via DynamicDependency below"), + DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Linq.Expressions.AssignBinaryExpression", "System.Linq.Expressions")] public static Expression Assign( this MemberExpression memberExpression, Expression valueExpression) @@ -447,7 +446,7 @@ static Expression AddConvertToObject(Expression expression) /// The model being used. /// The given expression, with the top-level member access node removed. /// - /// if represents a member access, otherwise. + /// if represents a member access, otherwise. /// public static bool IsMemberAccess( Expression expression, @@ -464,7 +463,7 @@ public static bool IsMemberAccess( /// The given expression, with the top-level member access node removed. /// A representing the member being accessed. /// - /// if represents a member access, otherwise. + /// if represents a member access, otherwise. /// public static bool IsMemberAccess( Expression expression, diff --git a/src/EFCore/Infrastructure/IInternalServiceCollectionMap.cs b/src/EFCore/Infrastructure/IInternalServiceCollectionMap.cs index de142e5be29..41c4b811209 100644 --- a/src/EFCore/Infrastructure/IInternalServiceCollectionMap.cs +++ b/src/EFCore/Infrastructure/IInternalServiceCollectionMap.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Infrastructure; /// diff --git a/src/EFCore/Infrastructure/IndentedStringBuilder.cs b/src/EFCore/Infrastructure/IndentedStringBuilder.cs index c77d21c3954..c72b20c8f94 100644 --- a/src/EFCore/Infrastructure/IndentedStringBuilder.cs +++ b/src/EFCore/Infrastructure/IndentedStringBuilder.cs @@ -291,7 +291,7 @@ public virtual IDisposable SuspendIndent() => new IndentSuspender(this); /// - /// Clones this , copying the built string and current indent level. + /// Clones this , copying the built string and current indent level. /// /// New instance of . public virtual IndentedStringBuilder Clone() diff --git a/src/EFCore/Infrastructure/Internal/DbSetFinder.cs b/src/EFCore/Infrastructure/Internal/DbSetFinder.cs index bab939cc544..e931bebc558 100644 --- a/src/EFCore/Infrastructure/Internal/DbSetFinder.cs +++ b/src/EFCore/Infrastructure/Internal/DbSetFinder.cs @@ -30,18 +30,16 @@ private static DbSetProperty[] FindSetsNonCached(Type contextType) var factory = ClrPropertySetterFactory.Instance; return contextType.GetRuntimeProperties() - .Where( - p => !p.IsStatic() - && !p.GetIndexParameters().Any() - && p.DeclaringType != typeof(DbContext) - && p.PropertyType.GetTypeInfo().IsGenericType - && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)) + .Where(p => !p.IsStatic() + && !p.GetIndexParameters().Any() + && p.DeclaringType != typeof(DbContext) + && p.PropertyType.GetTypeInfo().IsGenericType + && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)) .OrderBy(p => p.Name) - .Select( - p => new DbSetProperty( - p.Name, - p.PropertyType.GenericTypeArguments.Single(), - p.SetMethod == null ? null : factory.Create(p))) + .Select(p => new DbSetProperty( + p.Name, + p.PropertyType.GenericTypeArguments.Single(), + p.SetMethod == null ? null : factory.Create(p))) .ToArray(); } } diff --git a/src/EFCore/Infrastructure/Internal/InternalServiceCollectionMap.cs b/src/EFCore/Infrastructure/Internal/InternalServiceCollectionMap.cs index 84d1ed9108c..a77a5d7ab53 100644 --- a/src/EFCore/Infrastructure/Internal/InternalServiceCollectionMap.cs +++ b/src/EFCore/Infrastructure/Internal/InternalServiceCollectionMap.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Infrastructure.Internal; diff --git a/src/EFCore/Infrastructure/Internal/LazyLoader.cs b/src/EFCore/Infrastructure/Internal/LazyLoader.cs index b5c49fc197d..240cc775c29 100644 --- a/src/EFCore/Infrastructure/Internal/LazyLoader.cs +++ b/src/EFCore/Infrastructure/Internal/LazyLoader.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.EntityFrameworkCore.Internal; @@ -20,8 +19,11 @@ public class LazyLoader : ILazyLoader, IInjectableService private bool _disposed; private bool _detached; private IDictionary? _loadedStates; - private readonly Lock _isLoadingLock = new Lock(); - private readonly Dictionary<(object Entity, string NavigationName), TaskCompletionSource> _isLoading = new(NavEntryEqualityComparer.Instance); + private readonly Lock _isLoadingLock = new(); + + private readonly Dictionary<(object Entity, string NavigationName), TaskCompletionSource> _isLoading = new( + NavEntryEqualityComparer.Instance); + private static readonly AsyncLocal _isLoadingCallDepth = new(); private HashSet? _nonLazyNavigations; @@ -118,8 +120,9 @@ public virtual void Load(object entity, [CallerMemberName] string navigationName ref var refIsLoadingValue = ref CollectionsMarshal.GetValueRefOrAddDefault(_isLoading, navEntry, out exists); if (!exists) { - refIsLoadingValue = new(); + refIsLoadingValue = new TaskCompletionSource(); } + _isLoadingCallDepth.Value++; isLoadingValue = refIsLoadingValue!; } @@ -132,6 +135,7 @@ public virtual void Load(object entity, [CallerMemberName] string navigationName { isLoadingValue.Task.Wait(); } + _isLoadingCallDepth.Value--; return; } @@ -190,8 +194,9 @@ public virtual async Task LoadAsync( ref var refIsLoadingValue = ref CollectionsMarshal.GetValueRefOrAddDefault(_isLoading, navEntry, out exists); if (!exists) { - refIsLoadingValue = new(); + refIsLoadingValue = new TaskCompletionSource(); } + _isLoadingCallDepth.Value++; isLoadingValue = refIsLoadingValue!; } @@ -204,6 +209,7 @@ public virtual async Task LoadAsync( { await isLoadingValue.Task.WaitAsync(cancellationToken).ConfigureAwait(false); } + _isLoadingCallDepth.Value--; return; } @@ -216,10 +222,10 @@ public virtual async Task LoadAsync( try { await entry.LoadAsync( - _queryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution - ? LoadOptions.ForceIdentityResolution - : LoadOptions.None, - cancellationToken).ConfigureAwait(false); + _queryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution + ? LoadOptions.ForceIdentityResolution + : LoadOptions.None, + cancellationToken).ConfigureAwait(false); } catch { diff --git a/src/EFCore/Infrastructure/ModelValidator.cs b/src/EFCore/Infrastructure/ModelValidator.cs index 346193b7137..6a578a6df46 100644 --- a/src/EFCore/Infrastructure/ModelValidator.cs +++ b/src/EFCore/Infrastructure/ModelValidator.cs @@ -147,13 +147,16 @@ protected virtual void ValidatePropertyMapping( /// The type base to validate. /// The model to validate. /// The logger to use. - protected virtual void ValidatePropertyMapping(IConventionTypeBase structuralType, IConventionModel model, IDiagnosticsLogger logger) + protected virtual void ValidatePropertyMapping( + IConventionTypeBase structuralType, + IConventionModel model, + IDiagnosticsLogger logger) { - var unmappedProperty = structuralType.GetDeclaredProperties().FirstOrDefault( - p => (!ConfigurationSource.Convention.Overrides(p.GetConfigurationSource()) - // Use a better condition for non-persisted properties when issue #14121 is implemented - || !p.IsImplicitlyCreated()) - && p.FindTypeMapping() == null); + var unmappedProperty = structuralType.GetDeclaredProperties().FirstOrDefault(p + => (!ConfigurationSource.Convention.Overrides(p.GetConfigurationSource()) + // Use a better condition for non-persisted properties when issue #14121 is implemented + || !p.IsImplicitlyCreated()) + && p.FindTypeMapping() == null); if (unmappedProperty != null) { @@ -245,9 +248,9 @@ protected virtual void ValidatePropertyMapping(IConventionTypeBase structuralTyp if ((isAdHoc || !entityType.IsKeyless || targetSequenceType == null) - && entityType.GetDerivedTypes().All( - dt => dt.GetDeclaredNavigations().FirstOrDefault(n => n.Name == clrProperty.GetSimpleMemberName()) - == null) + && entityType.GetDerivedTypes().All(dt + => dt.GetDeclaredNavigations().FirstOrDefault(n => n.Name == clrProperty.GetSimpleMemberName()) + == null) && (!(targetShared || targetOwned.Value) || !targetType.Equals(entityType.ClrType)) && (!entityType.IsInOwnershipPath(targetType) @@ -302,7 +305,9 @@ protected virtual void ValidatePropertyMapping(IConventionTypeBase structuralTyp /// /// The complex property to validate. /// The logger to use. - protected virtual void ValidatePropertyMapping(IConventionComplexProperty complexProperty, IDiagnosticsLogger logger) + protected virtual void ValidatePropertyMapping( + IConventionComplexProperty complexProperty, + IDiagnosticsLogger logger) { var structuralType = complexProperty.DeclaringType; @@ -685,6 +690,7 @@ protected virtual void ValidateDiscriminatorValues(IEntityType rootEntityType) { ValidateDiscriminatorValues(complexProperty.ComplexType); } + return; } @@ -857,11 +863,10 @@ protected virtual void ValidateOwnership( throw new InvalidOperationException(CoreStrings.OwnedDerivedType(entityType.DisplayName())); } - foreach (var referencingFk in entityType.GetReferencingForeignKeys().Where( - fk => !fk.IsOwnership - && (fk.PrincipalEntityType != fk.DeclaringEntityType - || !fk.Properties.SequenceEqual(entityType.FindPrimaryKey()!.Properties)) - && !Contains(fk.DeclaringEntityType.FindOwnership(), fk))) + foreach (var referencingFk in entityType.GetReferencingForeignKeys().Where(fk => !fk.IsOwnership + && (fk.PrincipalEntityType != fk.DeclaringEntityType + || !fk.Properties.SequenceEqual(entityType.FindPrimaryKey()!.Properties)) + && !Contains(fk.DeclaringEntityType.FindOwnership(), fk))) { throw new InvalidOperationException( CoreStrings.PrincipalOwnedType( @@ -876,9 +881,9 @@ protected virtual void ValidateOwnership( entityType.DisplayName())); } - foreach (var fk in entityType.GetDeclaredForeignKeys().Where( - fk => fk is { IsOwnership: false, PrincipalToDependent: not null } - && !Contains(fk.DeclaringEntityType.FindOwnership(), fk))) + foreach (var fk in entityType.GetDeclaredForeignKeys().Where(fk + => fk is { IsOwnership: false, PrincipalToDependent: not null } + && !Contains(fk.DeclaringEntityType.FindOwnership(), fk))) { throw new InvalidOperationException( CoreStrings.InverseToOwnedType( @@ -953,9 +958,8 @@ protected virtual void ValidateForeignKeys( static bool ContainedInForeignKeyForAllConcreteTypes(IEntityType entityType, IProperty property) => entityType.ClrType.IsAbstract && entityType.GetDerivedTypes().Where(t => !t.ClrType.IsAbstract) - .All( - d => d.GetForeignKeys() - .Any(fk => fk.Properties.Contains(property))); + .All(d => d.GetForeignKeys() + .Any(fk => fk.Properties.Contains(property))); } /// @@ -1055,11 +1059,12 @@ static void Validate(ITypeBase structuralType) if (complexProperty.IsCollection && !complexProperty.ClrType.GetGenericTypeImplementations(typeof(IList<>)).Any()) { - throw new InvalidOperationException(CoreStrings.NonListCollection( - complexProperty.DeclaringType.DisplayName(), - complexProperty.Name, - complexProperty.ClrType.ShortDisplayName(), - $"IList<{complexProperty.ComplexType.ClrType.ShortDisplayName()}>")); + throw new InvalidOperationException( + CoreStrings.NonListCollection( + complexProperty.DeclaringType.DisplayName(), + complexProperty.Name, + complexProperty.ClrType.ShortDisplayName(), + $"IList<{complexProperty.ComplexType.ClrType.ShortDisplayName()}>")); } Validate(complexProperty.ComplexType); @@ -1232,10 +1237,9 @@ protected virtual void ValidateQueryFilters( // So we don't check navigations there. We assume the owner will propagate filtering var requiredNavigationWithQueryFilter = entityType .GetNavigations() - .FirstOrDefault( - n => n is { IsCollection: false, ForeignKey.IsRequired: true, IsOnDependent: true } - && n.ForeignKey.PrincipalEntityType.GetRootType().GetDeclaredQueryFilters().Count > 0 - && n.ForeignKey.DeclaringEntityType.GetRootType().GetDeclaredQueryFilters().Count == 0); + .FirstOrDefault(n => n is { IsCollection: false, ForeignKey.IsRequired: true, IsOnDependent: true } + && n.ForeignKey.PrincipalEntityType.GetRootType().GetDeclaredQueryFilters().Count > 0 + && n.ForeignKey.DeclaringEntityType.GetRootType().GetDeclaredQueryFilters().Count == 0); if (requiredNavigationWithQueryFilter != null) { diff --git a/src/EFCore/Infrastructure/PooledDbContextFactory.cs b/src/EFCore/Infrastructure/PooledDbContextFactory.cs index c99a8b878b9..6ceebdf2930 100644 --- a/src/EFCore/Infrastructure/PooledDbContextFactory.cs +++ b/src/EFCore/Infrastructure/PooledDbContextFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Infrastructure; diff --git a/src/EFCore/Metadata/RuntimeAnnotatableBase.cs b/src/EFCore/Infrastructure/RuntimeAnnotatableBase.cs similarity index 99% rename from src/EFCore/Metadata/RuntimeAnnotatableBase.cs rename to src/EFCore/Infrastructure/RuntimeAnnotatableBase.cs index ebe86f5b23e..a80ebb2cb9e 100644 --- a/src/EFCore/Metadata/RuntimeAnnotatableBase.cs +++ b/src/EFCore/Infrastructure/RuntimeAnnotatableBase.cs @@ -204,7 +204,7 @@ protected virtual Annotation CreateAnnotation(string name, object? value) /// public virtual IEnumerable GetRuntimeAnnotations() => _runtimeAnnotations?.OrderBy(p => p.Key, StringComparer.Ordinal).Select(p => p.Value) - ?? Enumerable.Empty(); + ?? []; /// /// Adds a runtime annotation to this object. Throws if an annotation with the specified name already exists. diff --git a/src/EFCore/Infrastructure/ServiceCollectionMap.cs b/src/EFCore/Infrastructure/ServiceCollectionMap.cs index 82639bfc533..be346fa4e72 100644 --- a/src/EFCore/Infrastructure/ServiceCollectionMap.cs +++ b/src/EFCore/Infrastructure/ServiceCollectionMap.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Infrastructure.Internal; namespace Microsoft.EntityFrameworkCore.Infrastructure; diff --git a/src/EFCore/Internal/DbContextFactory.cs b/src/EFCore/Internal/DbContextFactory.cs index 0d266e2c5c1..3406d7aa998 100644 --- a/src/EFCore/Internal/DbContextFactory.cs +++ b/src/EFCore/Internal/DbContextFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Internal; /// diff --git a/src/EFCore/Internal/DbContextLease.cs b/src/EFCore/Internal/DbContextLease.cs index 925493151e6..d8b9db18128 100644 --- a/src/EFCore/Internal/DbContextLease.cs +++ b/src/EFCore/Internal/DbContextLease.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Internal; /// diff --git a/src/EFCore/Internal/DbContextPool.cs b/src/EFCore/Internal/DbContextPool.cs index eba778ba06c..ac42f86e9a1 100644 --- a/src/EFCore/Internal/DbContextPool.cs +++ b/src/EFCore/Internal/DbContextPool.cs @@ -55,7 +55,7 @@ private static Func CreateActivator(DbContextOptions option .Where(c => c is { IsStatic: false, IsPublic: true } && c.GetParameters().Length > 0).ToArray(); if (constructors.Length == 1 - && constructors[0].GetParameters() is { } parameters + && constructors[0].GetParameters() is var parameters && parameters.Any(p => p.ParameterType == typeof(DbContextOptions) || p.ParameterType == typeof(DbContextOptions))) { if (parameters.Length == 1) diff --git a/src/EFCore/Internal/DbContextServices.cs b/src/EFCore/Internal/DbContextServices.cs index d7b3ddde953..cd9b61b29d6 100644 --- a/src/EFCore/Internal/DbContextServices.cs +++ b/src/EFCore/Internal/DbContextServices.cs @@ -18,8 +18,6 @@ public class DbContextServices : IDbContextServices private IServiceProvider? _scopedProvider; private DbContextOptions? _contextOptions; private ICurrentDbContext? _currentContext; - private IModel? _model; - private IModel? _designTimeModel; private bool _inOnModelCreating; /// @@ -156,8 +154,9 @@ public virtual ICurrentDbContext CurrentContext /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual IModel Model - => _model ??= CreateModel(designTime: false); + => field ??= CreateModel(designTime: false); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -165,8 +164,9 @@ public virtual IModel Model /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual IModel DesignTimeModel - => _designTimeModel ??= CreateModel(designTime: true); + => field ??= CreateModel(designTime: true); private CoreOptionsExtension? CoreOptions => _contextOptions?.FindExtension(); diff --git a/src/EFCore/Internal/EntityFinder.cs b/src/EFCore/Internal/EntityFinder.cs index 980d38d8ef5..904bf22ddf4 100644 --- a/src/EFCore/Internal/EntityFinder.cs +++ b/src/EFCore/Internal/EntityFinder.cs @@ -148,8 +148,8 @@ public virtual IEnumerable GetEntries(IProperty if (TryFindByKey(property, propertyValue, out var entry)) { return entry != null - ? new[] { entry } - : Enumerable.Empty(); + ? [entry] + : []; } if (TryGetByForeignKey(property, propertyValue, out var entries)) @@ -216,8 +216,8 @@ public virtual IEnumerable GetEntries(IEnumerable(); + ? [entry] + : []; } if (TryGetByForeignKey(propertiesList, valuesList, out var entries)) @@ -802,7 +802,7 @@ private static Expression> BuildObjectLambda(IReadOnlyList entityType.FindOwnership() is IForeignKey ownership + => entityType.FindOwnership() is { } ownership ? BuildQueryRoot(ownership.PrincipalEntityType, entityType, ownership.PrincipalToDependent!.Name) : entityType.HasSharedClrType ? (IQueryable)_setCache.GetOrAddSet(_setSource, entityType.Name, entityType.ClrType) diff --git a/src/EFCore/Internal/IDbSetCache.cs b/src/EFCore/Internal/IDbSetCache.cs index f988750347e..3d2e00f9f00 100644 --- a/src/EFCore/Internal/IDbSetCache.cs +++ b/src/EFCore/Internal/IDbSetCache.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Internal; /// diff --git a/src/EFCore/Internal/IDbSetSource.cs b/src/EFCore/Internal/IDbSetSource.cs index dda703c0107..10f3191d7ea 100644 --- a/src/EFCore/Internal/IDbSetSource.cs +++ b/src/EFCore/Internal/IDbSetSource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Internal; /// diff --git a/src/EFCore/Internal/InternalDbSet.cs b/src/EFCore/Internal/InternalDbSet.cs index 907acb7568a..66ab6fa869e 100644 --- a/src/EFCore/Internal/InternalDbSet.cs +++ b/src/EFCore/Internal/InternalDbSet.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query.Internal; @@ -26,10 +25,7 @@ public class InternalDbSet<[DynamicallyAccessedMembers(IEntityType.DynamicallyAc { private readonly DbContext _context; private readonly string? _entityTypeName; - private IEntityType? _entityType; - private EntityQueryable? _entityQueryable; private LocalView? _localView; - private IEntityFinder? _finder; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -51,20 +47,21 @@ public InternalDbSet(DbContext context, string? entityTypeName) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public override IEntityType EntityType { get { - if (_entityType != null) + if (field != null) { - return _entityType; + return field; } - _entityType = _entityTypeName != null + field = _entityTypeName != null ? _context.Model.FindEntityType(_entityTypeName) : _context.Model.FindEntityType(typeof(TEntity)); - if (_entityType == null) + if (field == null) { if (_context.Model.IsShared(typeof(TEntity))) { @@ -82,25 +79,25 @@ public override IEntityType EntityType throw new InvalidOperationException(CoreStrings.InvalidSetType(typeof(TEntity).ShortDisplayName())); } - if (_entityType.IsOwned()) + if (field.IsOwned()) { var message = CoreStrings.InvalidSetTypeOwned( - _entityType.DisplayName(), _entityType.FindOwnership()!.PrincipalEntityType.DisplayName()); - _entityType = null; + field.DisplayName(), field.FindOwnership()!.PrincipalEntityType.DisplayName()); + field = null; throw new InvalidOperationException(message); } - if (_entityType.ClrType != typeof(TEntity)) + if (field.ClrType != typeof(TEntity)) { var message = CoreStrings.DbSetIncorrectGenericType( - _entityType.ShortName(), _entityType.ClrType.ShortDisplayName(), typeof(TEntity).ShortDisplayName()); - _entityType = null; + field.ShortName(), field.ClrType.ShortDisplayName(), typeof(TEntity).ShortDisplayName()); + field = null; throw new InvalidOperationException(message); } - return _entityType; + return field; } } @@ -116,6 +113,7 @@ private void CheckKey() } } + [field: AllowNull, MaybeNull] private EntityQueryable EntityQueryable { get @@ -123,7 +121,7 @@ private EntityQueryable EntityQueryable CheckState(); return NonCapturingLazyInitializer.EnsureInitialized( - ref _entityQueryable, + ref field, this, static internalSet => internalSet.CreateEntityQueryable()); } @@ -449,21 +447,22 @@ public override EntityEntry Entry(TEntity entity) return entry; } + [field: AllowNull, MaybeNull] private IEntityFinder Finder { get { - if (_finder == null) + if (field == null) { if (EntityType.FindPrimaryKey() == null) { throw new InvalidOperationException(CoreStrings.InvalidSetKeylessOperation(EntityType.DisplayName())); } - _finder = (IEntityFinder)_context.GetDependencies().EntityFinderFactory.Create(EntityType); + field = (IEntityFinder)_context.GetDependencies().EntityFinderFactory.Create(EntityType); } - return _finder; + return field; } } diff --git a/src/EFCore/Metadata/AdHocMapper.cs b/src/EFCore/Metadata/AdHocMapper.cs index 73e041ca4ea..2e3a25cba26 100644 --- a/src/EFCore/Metadata/AdHocMapper.cs +++ b/src/EFCore/Metadata/AdHocMapper.cs @@ -22,8 +22,6 @@ namespace Microsoft.EntityFrameworkCore.Metadata; /// public class AdHocMapper : IAdHocMapper { - private ConventionSet? _conventionSet; - /// /// Do not call this constructor directly from either provider or application code as it may change /// as new dependencies are added. Instead, use this type in your constructor so that an instance @@ -76,8 +74,9 @@ public virtual ConventionSet BuildConventionSet() return conventionSet; } + [field: AllowNull, MaybeNull] private ConventionSet ConventionSet - => (_conventionSet ??= BuildConventionSet()); + => (field ??= BuildConventionSet()); /// public virtual RuntimeEntityType GetOrAddEntityType(Type clrType) diff --git a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs index b73b48e0423..66045f00bcd 100644 --- a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs +++ b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/CollectionNavigationBuilder`.cs b/src/EFCore/Metadata/Builders/CollectionNavigationBuilder`.cs index 75a0eedc2e0..f46fdca9026 100644 --- a/src/EFCore/Metadata/Builders/CollectionNavigationBuilder`.cs +++ b/src/EFCore/Metadata/Builders/CollectionNavigationBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/ComplexCollectionBuilder.cs b/src/EFCore/Metadata/Builders/ComplexCollectionBuilder.cs index e27b4011792..8fa60e248dc 100644 --- a/src/EFCore/Metadata/Builders/ComplexCollectionBuilder.cs +++ b/src/EFCore/Metadata/Builders/ComplexCollectionBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -262,7 +261,7 @@ public virtual ComplexCollectionTypePropertyBuilder IndexerProperty( { Check.NotNull(propertyType); - return new( + return new ComplexCollectionTypePropertyBuilder( TypeBuilder.IndexerProperty( propertyType, Check.NotEmpty(propertyName), ConfigurationSource.Explicit)!.Metadata); @@ -674,7 +673,9 @@ public virtual ComplexCollectionBuilder ComplexCollection(string propertyName, A /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual ComplexCollectionBuilder ComplexCollection(string propertyName, Action> buildAction) + public virtual ComplexCollectionBuilder ComplexCollection( + string propertyName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull { @@ -703,7 +704,9 @@ public virtual ComplexCollectionBuilder ComplexCollection(s /// An action that performs configuration of the property. /// An object that can be used to configure the property. public virtual ComplexCollectionBuilder ComplexCollection( - string propertyName, string complexTypeName, Action> buildAction) + string propertyName, + string complexTypeName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull { @@ -729,7 +732,10 @@ public virtual ComplexCollectionBuilder ComplexCollection( /// The name of the property to be configured. /// An action that performs configuration of the property. /// The same builder instance so that multiple configuration calls can be chained. - public virtual ComplexCollectionBuilder ComplexCollection(Type propertyType, string propertyName, Action buildAction) + public virtual ComplexCollectionBuilder ComplexCollection( + Type propertyType, + string propertyName, + Action buildAction) { Check.NotNull(buildAction); @@ -754,7 +760,11 @@ public virtual ComplexCollectionBuilder ComplexCollection(Type propertyType, str /// The name of the complex type. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual ComplexCollectionBuilder ComplexCollection(Type propertyType, string propertyName, string complexTypeName, Action buildAction) + public virtual ComplexCollectionBuilder ComplexCollection( + Type propertyType, + string propertyName, + string complexTypeName, + Action buildAction) { Check.NotNull(buildAction); diff --git a/src/EFCore/Metadata/Builders/ComplexCollectionBuilder`.cs b/src/EFCore/Metadata/Builders/ComplexCollectionBuilder`.cs index 80571690313..71cf58a58ad 100644 --- a/src/EFCore/Metadata/Builders/ComplexCollectionBuilder`.cs +++ b/src/EFCore/Metadata/Builders/ComplexCollectionBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// @@ -32,7 +30,6 @@ public ComplexCollectionBuilder(IMutableComplexProperty complexProperty) { } - /// /// Adds or updates an annotation on the complex property. If an annotation with the key specified in /// already exists its value will be updated. @@ -72,7 +69,8 @@ public ComplexCollectionBuilder(IMutableComplexProperty complexProperty) /// blog => blog.Url). /// /// An object that can be used to configure the property. - public virtual ComplexCollectionTypePropertyBuilder Property(Expression> propertyExpression) + public virtual ComplexCollectionTypePropertyBuilder Property( + Expression> propertyExpression) => new( TypeBuilder.Property( Check.NotNull(propertyExpression).GetMemberAccess(), ConfigurationSource.Explicit)! @@ -446,7 +444,9 @@ public virtual ComplexCollectionBuilder ComplexProperty( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public new virtual ComplexCollectionBuilder ComplexCollection(string propertyName, Action buildAction) + public new virtual ComplexCollectionBuilder ComplexCollection( + string propertyName, + Action buildAction) => (ComplexCollectionBuilder)base.ComplexCollection(propertyName, buildAction); /// @@ -466,7 +466,8 @@ public virtual ComplexCollectionBuilder ComplexProperty( /// An action that performs configuration of the property. /// An object that can be used to configure the property. public new virtual ComplexCollectionBuilder ComplexCollection( - string propertyName, Action> buildAction) + string propertyName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull => (ComplexCollectionBuilder)base.ComplexCollection(propertyName, buildAction); @@ -511,7 +512,10 @@ public virtual ComplexCollectionBuilder ComplexProperty( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public new virtual ComplexCollectionBuilder ComplexCollection(Type propertyType, string propertyName, Action buildAction) + public new virtual ComplexCollectionBuilder ComplexCollection( + Type propertyType, + string propertyName, + Action buildAction) => (ComplexCollectionBuilder)base.ComplexCollection(propertyType, propertyName, buildAction); /// @@ -531,7 +535,10 @@ public virtual ComplexCollectionBuilder ComplexProperty( /// An action that performs configuration of the property. /// An object that can be used to configure the property. public new virtual ComplexCollectionBuilder ComplexCollection( - Type propertyType, string propertyName, string complexTypeName, Action buildAction) + Type propertyType, + string propertyName, + string complexTypeName, + Action buildAction) => (ComplexCollectionBuilder)base.ComplexCollection(propertyType, complexTypeName, propertyName, buildAction); /// diff --git a/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder.cs b/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder.cs index 6a27c5dbb2d..4a93657bf60 100644 --- a/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder.cs +++ b/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder`.cs b/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder`.cs index de6fd0abe56..9bc135f7912 100644 --- a/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder`.cs +++ b/src/EFCore/Metadata/Builders/ComplexCollectionTypePropertyBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/ComplexPropertyBuilder.cs b/src/EFCore/Metadata/Builders/ComplexPropertyBuilder.cs index c2f4ba61d2a..ab082ed3c08 100644 --- a/src/EFCore/Metadata/Builders/ComplexPropertyBuilder.cs +++ b/src/EFCore/Metadata/Builders/ComplexPropertyBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -712,7 +711,9 @@ public virtual ComplexPropertyBuilder ComplexCollection(string propertyName, Act /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual ComplexPropertyBuilder ComplexCollection(string propertyName, Action> buildAction) + public virtual ComplexPropertyBuilder ComplexCollection( + string propertyName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull { @@ -741,7 +742,9 @@ public virtual ComplexPropertyBuilder ComplexCollection(str /// An action that performs configuration of the property. /// An object that can be used to configure the property. public virtual ComplexPropertyBuilder ComplexCollection( - string propertyName, string complexTypeName, Action> buildAction) + string propertyName, + string complexTypeName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull { @@ -767,7 +770,10 @@ public virtual ComplexPropertyBuilder ComplexCollection( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual ComplexPropertyBuilder ComplexCollection(Type propertyType, string propertyName, Action buildAction) + public virtual ComplexPropertyBuilder ComplexCollection( + Type propertyType, + string propertyName, + Action buildAction) { Check.NotNull(buildAction); @@ -792,7 +798,11 @@ public virtual ComplexPropertyBuilder ComplexCollection(Type propertyType, strin /// The name of the complex type. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual ComplexPropertyBuilder ComplexCollection(Type propertyType, string propertyName, string complexTypeName, Action buildAction) + public virtual ComplexPropertyBuilder ComplexCollection( + Type propertyType, + string propertyName, + string complexTypeName, + Action buildAction) { Check.NotNull(buildAction); diff --git a/src/EFCore/Metadata/Builders/ComplexPropertyBuilder`.cs b/src/EFCore/Metadata/Builders/ComplexPropertyBuilder`.cs index 8ece80c7f6f..733198f0262 100644 --- a/src/EFCore/Metadata/Builders/ComplexPropertyBuilder`.cs +++ b/src/EFCore/Metadata/Builders/ComplexPropertyBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// @@ -488,7 +486,9 @@ public virtual ComplexPropertyBuilder ComplexProperty( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public new virtual ComplexPropertyBuilder ComplexCollection(string propertyName, Action> buildAction) + public new virtual ComplexPropertyBuilder ComplexCollection( + string propertyName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull => (ComplexPropertyBuilder)base.ComplexCollection(propertyName, buildAction); @@ -533,7 +533,10 @@ public virtual ComplexPropertyBuilder ComplexProperty( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public new virtual ComplexPropertyBuilder ComplexCollection(Type propertyType, string propertyName, Action buildAction) + public new virtual ComplexPropertyBuilder ComplexCollection( + Type propertyType, + string propertyName, + Action buildAction) => (ComplexPropertyBuilder)base.ComplexCollection(propertyType, propertyName, buildAction); /// @@ -553,7 +556,10 @@ public virtual ComplexPropertyBuilder ComplexProperty( /// An action that performs configuration of the property. /// An object that can be used to configure the property. public new virtual ComplexPropertyBuilder ComplexCollection( - Type propertyType, string propertyName, string complexTypeName, Action buildAction) + Type propertyType, + string propertyName, + string complexTypeName, + Action buildAction) => (ComplexPropertyBuilder)base.ComplexCollection(propertyType, propertyName, complexTypeName, buildAction); /// diff --git a/src/EFCore/Metadata/Builders/ComplexTypeDiscriminatorBuilder.cs b/src/EFCore/Metadata/Builders/ComplexTypeDiscriminatorBuilder.cs index 3f352a33375..f25a7312eee 100644 --- a/src/EFCore/Metadata/Builders/ComplexTypeDiscriminatorBuilder.cs +++ b/src/EFCore/Metadata/Builders/ComplexTypeDiscriminatorBuilder.cs @@ -98,7 +98,8 @@ IConventionComplexType IConventionComplexTypeDiscriminatorBuilder.ComplexType /// bool IConventionComplexTypeDiscriminatorBuilder.CanSetValue(object? value, bool fromDataAnnotation) - => ((IConventionComplexTypeBuilder)ComplexTypeBuilder).CanSetAnnotation(CoreAnnotationNames.DiscriminatorValue, value, fromDataAnnotation); + => ((IConventionComplexTypeBuilder)ComplexTypeBuilder).CanSetAnnotation( + CoreAnnotationNames.DiscriminatorValue, value, fromDataAnnotation); #region Hidden System.Object members diff --git a/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder.cs b/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder.cs index 2c31156697e..ddd4b193519 100644 --- a/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder.cs +++ b/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder`.cs b/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder`.cs index a84cb543c19..4fa3997df01 100644 --- a/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder`.cs +++ b/src/EFCore/Metadata/Builders/ComplexTypePrimitiveCollectionBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder.cs b/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder.cs index e61ea38c1f8..8e06b8f6be7 100644 --- a/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder.cs +++ b/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder`.cs b/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder`.cs index ff0be4a29d3..a88513f0c8b 100644 --- a/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder`.cs +++ b/src/EFCore/Metadata/Builders/ComplexTypePropertyBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/DiscriminatorBuilder.cs b/src/EFCore/Metadata/Builders/DiscriminatorBuilder.cs index a191b5e0caf..98edef0cb1a 100644 --- a/src/EFCore/Metadata/Builders/DiscriminatorBuilder.cs +++ b/src/EFCore/Metadata/Builders/DiscriminatorBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; diff --git a/src/EFCore/Metadata/Builders/DiscriminatorBuilder`.cs b/src/EFCore/Metadata/Builders/DiscriminatorBuilder`.cs index aaef601555b..56a30ca16d3 100644 --- a/src/EFCore/Metadata/Builders/DiscriminatorBuilder`.cs +++ b/src/EFCore/Metadata/Builders/DiscriminatorBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/ElementTypeBuilder.cs b/src/EFCore/Metadata/Builders/ElementTypeBuilder.cs index e4221844fa8..33c63f3c20f 100644 --- a/src/EFCore/Metadata/Builders/ElementTypeBuilder.cs +++ b/src/EFCore/Metadata/Builders/ElementTypeBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs b/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs index 6282352068c..3a5f3b5826e 100644 --- a/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -677,7 +676,9 @@ public virtual EntityTypeBuilder ComplexCollection(string propertyName, ActionThe name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual EntityTypeBuilder ComplexCollection(string propertyName, Action> buildAction) + public virtual EntityTypeBuilder ComplexCollection( + string propertyName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull { @@ -706,7 +707,9 @@ public virtual EntityTypeBuilder ComplexCollection(string p /// An action that performs configuration of the property. /// An object that can be used to configure the property. public virtual EntityTypeBuilder ComplexCollection( - string propertyName, string complexTypeName, Action> buildAction) + string propertyName, + string complexTypeName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull { @@ -757,7 +760,11 @@ public virtual EntityTypeBuilder ComplexCollection(Type propertyType, string pro /// The name of the complex type. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public virtual EntityTypeBuilder ComplexCollection(Type propertyType, string propertyName, string complexTypeName, Action buildAction) + public virtual EntityTypeBuilder ComplexCollection( + Type propertyType, + string propertyName, + string complexTypeName, + Action buildAction) { Check.NotNull(buildAction); @@ -772,7 +779,7 @@ public virtual EntityTypeBuilder ComplexCollection(Type propertyType, string pro /// /// The name of the navigation property to be configured. /// An object that can be used to configure the navigation property. - /// + /// /// Navigation properties must first be added to the entity type using methods like HasOne, HasMany, /// or OwnsOne/OwnsMany before they can be configured with this method. /// @@ -813,7 +820,7 @@ public virtual EntityTypeBuilder HasQueryFilter(LambdaExpression? filter) /// The filter key /// The LINQ predicate expression. /// The same builder instance so that multiple configuration calls can be chained. - public virtual EntityTypeBuilder HasQueryFilter(string filterKey,LambdaExpression? filter) + public virtual EntityTypeBuilder HasQueryFilter(string filterKey, LambdaExpression? filter) { Builder.HasQueryFilter(new QueryFilter(filterKey, filter)); diff --git a/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs b/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs index 0fe91bfeed8..22c37b8bf82 100644 --- a/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs +++ b/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -478,7 +477,9 @@ public virtual EntityTypeBuilder ComplexProperty( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public new virtual EntityTypeBuilder ComplexCollection(string propertyName, Action> buildAction) + public new virtual EntityTypeBuilder ComplexCollection( + string propertyName, + Action> buildAction) where TProperty : IEnumerable where TElement : notnull => (EntityTypeBuilder)base.ComplexCollection(propertyName, buildAction); @@ -523,7 +524,10 @@ public virtual EntityTypeBuilder ComplexProperty( /// The name of the property to be configured. /// An action that performs configuration of the property. /// An object that can be used to configure the property. - public new virtual EntityTypeBuilder ComplexCollection(Type propertyType, string propertyName, Action buildAction) + public new virtual EntityTypeBuilder ComplexCollection( + Type propertyType, + string propertyName, + Action buildAction) => (EntityTypeBuilder)base.ComplexCollection(propertyType, propertyName, buildAction); /// @@ -543,7 +547,10 @@ public virtual EntityTypeBuilder ComplexProperty( /// An action that performs configuration of the property. /// An object that can be used to configure the property. public new virtual EntityTypeBuilder ComplexCollection( - Type propertyType, string propertyName, string complexTypeName, Action buildAction) + Type propertyType, + string propertyName, + string complexTypeName, + Action buildAction) => (EntityTypeBuilder)base.ComplexCollection(propertyType, propertyName, complexTypeName, buildAction); /// diff --git a/src/EFCore/Metadata/Builders/IConventionElementTypeBuilder.cs b/src/EFCore/Metadata/Builders/IConventionElementTypeBuilder.cs index 0e82892dde1..d0c65f86594 100644 --- a/src/EFCore/Metadata/Builders/IConventionElementTypeBuilder.cs +++ b/src/EFCore/Metadata/Builders/IConventionElementTypeBuilder.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/IConventionModelBuilder.cs b/src/EFCore/Metadata/Builders/IConventionModelBuilder.cs index 4a7bd139666..d5444522924 100644 --- a/src/EFCore/Metadata/Builders/IConventionModelBuilder.cs +++ b/src/EFCore/Metadata/Builders/IConventionModelBuilder.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs index 76368c12a15..45bd923102d 100644 --- a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs +++ b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs index a224013aefb..bbef525b1f0 100644 --- a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs +++ b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -145,11 +144,10 @@ public virtual KeyBuilder HasKey(params string[] propertyNames) /// The name of the property to be configured. /// An object that can be used to configure the property. public virtual PropertyBuilder Property(string propertyName) - => UpdateBuilder( - () => new PropertyBuilder( - DependentEntityType.Builder.Property( - Check.NotEmpty(propertyName), - ConfigurationSource.Explicit)!.Metadata)); + => UpdateBuilder(() => new PropertyBuilder( + DependentEntityType.Builder.Property( + Check.NotEmpty(propertyName), + ConfigurationSource.Explicit)!.Metadata)); /// /// Returns an object that can be used to configure a property of the owned entity type. @@ -166,11 +164,10 @@ public virtual PropertyBuilder Property(string propertyName) /// The name of the property to be configured. /// An object that can be used to configure the property. public virtual PropertyBuilder Property(string propertyName) - => UpdateBuilder( - () => new PropertyBuilder( - DependentEntityType.Builder.Property( - typeof(TProperty), - Check.NotEmpty(propertyName), ConfigurationSource.Explicit)!.Metadata)); + => UpdateBuilder(() => new PropertyBuilder( + DependentEntityType.Builder.Property( + typeof(TProperty), + Check.NotEmpty(propertyName), ConfigurationSource.Explicit)!.Metadata)); /// /// Returns an object that can be used to configure a property of the owned entity type. @@ -205,11 +202,10 @@ public virtual PropertyBuilder Property(Type propertyType, string propertyName) /// The name of the property to be configured. /// An object that can be used to configure the property. public virtual PrimitiveCollectionBuilder PrimitiveCollection(string propertyName) - => UpdateBuilder( - () => new PrimitiveCollectionBuilder( - DependentEntityType.Builder.PrimitiveCollection( - Check.NotEmpty(propertyName), - ConfigurationSource.Explicit)!.Metadata)); + => UpdateBuilder(() => new PrimitiveCollectionBuilder( + DependentEntityType.Builder.PrimitiveCollection( + Check.NotEmpty(propertyName), + ConfigurationSource.Explicit)!.Metadata)); /// /// Returns an object that can be used to configure a property of the owned type where that property represents @@ -227,11 +223,10 @@ public virtual PrimitiveCollectionBuilder PrimitiveCollection(string propertyNam /// The name of the property to be configured. /// An object that can be used to configure the property. public virtual PrimitiveCollectionBuilder PrimitiveCollection(string propertyName) - => UpdateBuilder( - () => new PrimitiveCollectionBuilder( - DependentEntityType.Builder.PrimitiveCollection( - typeof(TProperty), - Check.NotEmpty(propertyName), ConfigurationSource.Explicit)!.Metadata)); + => UpdateBuilder(() => new PrimitiveCollectionBuilder( + DependentEntityType.Builder.PrimitiveCollection( + typeof(TProperty), + Check.NotEmpty(propertyName), ConfigurationSource.Explicit)!.Metadata)); /// /// Returns an object that can be used to configure a property of the owned type where that property represents @@ -304,7 +299,7 @@ public virtual PropertyBuilder IndexerProperty( /// /// The name of the navigation property to be configured. /// An object that can be used to configure the navigation property. - /// + /// /// Navigation properties must first be added to the entity type using methods like HasOne, WithOwner, /// or OwnsOne/OwnsMany before they can be configured with this method. /// diff --git a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs index aa42ee058b3..b18e7826f56 100644 --- a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs +++ b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -89,11 +88,10 @@ public virtual KeyBuilder HasKey(ExpressionAn object that can be used to configure the property. public virtual PropertyBuilder Property( Expression> propertyExpression) - => UpdateBuilder( - () => new PropertyBuilder( - DependentEntityType.Builder.Property( - Check.NotNull(propertyExpression).GetMemberAccess(), - ConfigurationSource.Explicit)!.Metadata)); + => UpdateBuilder(() => new PropertyBuilder( + DependentEntityType.Builder.Property( + Check.NotNull(propertyExpression).GetMemberAccess(), + ConfigurationSource.Explicit)!.Metadata)); /// /// Returns an object that can be used to configure a property of the owned type where that property represents @@ -114,11 +112,10 @@ public virtual PropertyBuilder Property( /// An object that can be used to configure the property. public virtual PrimitiveCollectionBuilder PrimitiveCollection( Expression> propertyExpression) - => UpdateBuilder( - () => new PrimitiveCollectionBuilder( - DependentEntityType.Builder.PrimitiveCollection( - Check.NotNull(propertyExpression).GetMemberAccess(), - ConfigurationSource.Explicit)!.Metadata)); + => UpdateBuilder(() => new PrimitiveCollectionBuilder( + DependentEntityType.Builder.PrimitiveCollection( + Check.NotNull(propertyExpression).GetMemberAccess(), + ConfigurationSource.Explicit)!.Metadata)); /// /// Returns an object that can be used to configure an existing navigation property diff --git a/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs b/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs index 205bd994fac..6151b305a10 100644 --- a/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs +++ b/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder`.cs b/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder`.cs index 94816991020..c9fc1d41270 100644 --- a/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder`.cs +++ b/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Builders/PropertyBuilder.cs b/src/EFCore/Metadata/Builders/PropertyBuilder.cs index f9367a2473f..0c099f29c5b 100644 --- a/src/EFCore/Metadata/Builders/PropertyBuilder.cs +++ b/src/EFCore/Metadata/Builders/PropertyBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/EFCore/Metadata/Builders/PropertyBuilder`.cs b/src/EFCore/Metadata/Builders/PropertyBuilder`.cs index 1fcfcc40833..6084ec62f5e 100644 --- a/src/EFCore/Metadata/Builders/PropertyBuilder`.cs +++ b/src/EFCore/Metadata/Builders/PropertyBuilder`.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Builders; /// diff --git a/src/EFCore/Metadata/Conventions/ComplexPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ComplexPropertyDiscoveryConvention.cs index f10a4f278c9..9b13d6e9db3 100644 --- a/src/EFCore/Metadata/Conventions/ComplexPropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ComplexPropertyDiscoveryConvention.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; diff --git a/src/EFCore/Metadata/Conventions/DiscriminatorConvention.cs b/src/EFCore/Metadata/Conventions/DiscriminatorConvention.cs index 4d93d6cfe7f..4847487d79f 100644 --- a/src/EFCore/Metadata/Conventions/DiscriminatorConvention.cs +++ b/src/EFCore/Metadata/Conventions/DiscriminatorConvention.cs @@ -142,7 +142,5 @@ protected virtual void SetDefaultDiscriminatorValues( protected virtual void SetDefaultDiscriminatorValue( IConventionComplexType complexType, IConventionComplexTypeDiscriminatorBuilder discriminatorBuilder) - { - discriminatorBuilder.HasValue(complexType.GetDefaultDiscriminatorValue()); - } + => discriminatorBuilder.HasValue(complexType.GetDefaultDiscriminatorValue()); } diff --git a/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs b/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs index 0fa4c791da8..f9dac029672 100644 --- a/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs +++ b/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs @@ -10,7 +10,9 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// See Model building conventions for more information and examples. /// public class ElementTypeChangedConvention : - IPropertyElementTypeChangedConvention, IForeignKeyAddedConvention, IForeignKeyPropertiesChangedConvention + IPropertyElementTypeChangedConvention, + IForeignKeyAddedConvention, + IForeignKeyPropertiesChangedConvention { /// /// Creates a new instance of . diff --git a/src/EFCore/Metadata/Conventions/EntityTypeConfigurationAttributeConvention.cs b/src/EFCore/Metadata/Conventions/EntityTypeConfigurationAttributeConvention.cs index 36feaae5dd3..c230e850e38 100644 --- a/src/EFCore/Metadata/Conventions/EntityTypeConfigurationAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/EntityTypeConfigurationAttributeConvention.cs @@ -37,10 +37,9 @@ protected override void ProcessEntityTypeAdded( { var entityTypeConfigurationType = attribute.EntityTypeConfigurationType; - if (!entityTypeConfigurationType.GetInterfaces().Any( - x => x.IsGenericType - && x.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>) - && x.GenericTypeArguments[0] == entityTypeBuilder.Metadata.ClrType)) + if (!entityTypeConfigurationType.GetInterfaces().Any(x => x.IsGenericType + && x.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>) + && x.GenericTypeArguments[0] == entityTypeBuilder.Metadata.ClrType)) { throw new InvalidOperationException( CoreStrings.InvalidEntityTypeConfigurationAttribute( diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs index 9de7aced494..9a4d0a7052a 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs @@ -322,11 +322,10 @@ var fkPropertiesOnDependentToPrincipal if (existingProperties != null) { var conflictingFk = foreignKey.DeclaringEntityType.FindForeignKeys(existingProperties) - .FirstOrDefault( - fk => fk != foreignKey - && fk.PrincipalEntityType == foreignKey.PrincipalEntityType - && fk.GetConfigurationSource() == ConfigurationSource.DataAnnotation - && fk.GetPropertiesConfigurationSource() == ConfigurationSource.DataAnnotation); + .FirstOrDefault(fk => fk != foreignKey + && fk.PrincipalEntityType == foreignKey.PrincipalEntityType + && fk.GetConfigurationSource() == ConfigurationSource.DataAnnotation + && fk.GetPropertiesConfigurationSource() == ConfigurationSource.DataAnnotation); if (conflictingFk != null) { throw new InvalidOperationException( diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyIndexConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyIndexConvention.cs index 08b6e1357aa..4e3c896a4fc 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyIndexConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyIndexConvention.cs @@ -187,16 +187,16 @@ public virtual void ProcessEntityTypeBaseTypeChanged( } else if (newBaseType != null) { - var coveringKey = baseKeys!.FirstOrDefault( - k => AreIndexedBy(foreignKey.Properties, foreignKey.IsUnique, k.Properties, coveringIndexUnique: true)); + var coveringKey = baseKeys!.FirstOrDefault(k => AreIndexedBy( + foreignKey.Properties, foreignKey.IsUnique, k.Properties, coveringIndexUnique: true)); if (coveringKey != null) { RemoveIndex(index); } else { - var coveringIndex = baseIndexes!.FirstOrDefault( - i => AreIndexedBy(foreignKey.Properties, foreignKey.IsUnique, i.Properties, i.IsUnique)); + var coveringIndex = baseIndexes!.FirstOrDefault(i => AreIndexedBy( + foreignKey.Properties, foreignKey.IsUnique, i.Properties, i.IsUnique)); if (coveringIndex != null) { RemoveIndex(index); @@ -313,9 +313,8 @@ public virtual void ProcessIndexUniquenessChanged( { foreach (var foreignKey in index.DeclaringEntityType.GetDerivedTypesInclusive() .SelectMany(t => t.GetDeclaredForeignKeys()) - .Where( - fk => fk.IsUnique - && AreIndexedBy(fk.Properties, fk.IsUnique, index.Properties, coveringIndexUnique: true))) + .Where(fk => fk.IsUnique + && AreIndexedBy(fk.Properties, fk.IsUnique, index.Properties, coveringIndexUnique: true))) { CreateIndex(foreignKey.Properties, foreignKey.IsUnique, foreignKey.DeclaringEntityType.Builder); } diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs index 7fae234a577..a73dd0d3bef 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs @@ -205,7 +205,7 @@ private IConventionForeignKeyBuilder ProcessForeignKey( var invertedRelationshipBuilder = relationshipBuilder .HasEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType); if (invertedRelationshipBuilder is not null - && invertedRelationshipBuilder.Metadata is IConventionForeignKey invertedFk + && invertedRelationshipBuilder.Metadata is var invertedFk && invertedFk.IsSelfReferencing()) { invertedRelationshipBuilder = invertedRelationshipBuilder.HasNavigations( @@ -272,9 +272,8 @@ private IConventionForeignKeyBuilder ProcessForeignKey( && dependentPk.Properties.Count > foreignKey.PrincipalKey.Properties.Count && TryFindMatchingProperties(foreignKey, "", onDependent: true, matchPk: false, out foreignKeyProperties) && foreignKeyProperties != null - && foreignKeyProperties.Any( - p => !dependentPk.Properties.Contains(p) - || p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase))) + && foreignKeyProperties.Any(p => !dependentPk.Properties.Contains(p) + || p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase))) { foreignKeyProperties = null; } @@ -435,9 +434,8 @@ private bool TryFindMatchingProperties( if (matchFound && foreignKeyProperties.Length != 1 - && foreignKeyProperties.All( - p => p.IsImplicitlyCreated() - && ConfigurationSource.Convention.Overrides(p.GetConfigurationSource()))) + && foreignKeyProperties.All(p => p.IsImplicitlyCreated() + && ConfigurationSource.Convention.Overrides(p.GetConfigurationSource()))) { return false; } @@ -469,9 +467,8 @@ private bool TryFindMatchingProperties( dependentEntityType, shouldThrow: false)) { - if (propertiesToReference.All( - p => !p.IsImplicitlyCreated() - || p.GetConfigurationSource().Overrides(ConfigurationSource.DataAnnotation))) + if (propertiesToReference.All(p => !p.IsImplicitlyCreated() + || p.GetConfigurationSource().Overrides(ConfigurationSource.DataAnnotation))) { var dependentNavigationSpec = onDependent ? foreignKey.DependentToPrincipal?.Name @@ -878,9 +875,8 @@ public virtual void ProcessModelFinalizing( var conflictingForeignKey = foreignKey.DeclaringEntityType.FindForeignKeys(foreignKeyProperties).Concat( foreignKey.DeclaringEntityType.GetDerivedTypes() .SelectMany(et => et.FindDeclaredForeignKeys(foreignKeyProperties))) - .FirstOrDefault( - fk => fk != foreignKey - && ConfigurationSource.Convention.Overrides(fk.GetPropertiesConfigurationSource())); + .FirstOrDefault(fk => fk != foreignKey + && ConfigurationSource.Convention.Overrides(fk.GetPropertiesConfigurationSource())); if (conflictingForeignKey != null) { throw new InvalidOperationException( @@ -906,19 +902,22 @@ public virtual void ProcessModelFinalizing( continue; } - if (HasUniquifiedProperties(foreignKey)) + if (!HasUniquifiedProperties(foreignKey)) { - var conflictingFk = entityType.GetDeclaredForeignKeys().FirstOrDefault( - otherForeignKey => - otherForeignKey != foreignKey - && otherForeignKey.PrincipalEntityType == foreignKey.PrincipalEntityType - && otherForeignKey.GetPropertiesConfigurationSource() == null); - if (conflictingFk != null) - { - conflictingFkFound = true; - Dependencies.Logger.ConflictingShadowForeignKeysWarning(conflictingFk); - } + continue; + } + + var conflictingFk = entityType.GetDeclaredForeignKeys().FirstOrDefault(otherForeignKey => + otherForeignKey != foreignKey + && otherForeignKey.PrincipalEntityType == foreignKey.PrincipalEntityType + && otherForeignKey.GetPropertiesConfigurationSource() == null); + if (conflictingFk == null) + { + continue; } + + conflictingFkFound = true; + Dependencies.Logger.ConflictingShadowForeignKeysWarning(conflictingFk); } } } diff --git a/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.cs b/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.cs index 7fad1e7d49c..4e480e5568a 100644 --- a/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.cs +++ b/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal; diff --git a/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs b/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs index 44441eab278..9c4b5df1a9a 100644 --- a/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs @@ -79,13 +79,11 @@ private void Process( var targetClrType = targetEntityType.ClrType; var navigationCandidates = Dependencies.MemberClassifier.GetNavigationCandidates(targetEntityType, useAttributes: true); var inverseNavigationPropertyInfo = targetEntityType.GetRuntimeProperties().Values - .FirstOrDefault( - p => string.Equals(p.GetSimpleMemberName(), attribute.Property, StringComparison.Ordinal) - && navigationCandidates.ContainsKey(p)) + .FirstOrDefault(p => string.Equals(p.GetSimpleMemberName(), attribute.Property, StringComparison.Ordinal) + && navigationCandidates.ContainsKey(p)) ?? targetEntityType.GetRuntimeProperties().Values - .FirstOrDefault( - p => string.Equals(p.GetSimpleMemberName(), attribute.Property, StringComparison.OrdinalIgnoreCase) - && navigationCandidates.ContainsKey(p)); + .FirstOrDefault(p => string.Equals(p.GetSimpleMemberName(), attribute.Property, StringComparison.OrdinalIgnoreCase) + && navigationCandidates.ContainsKey(p)); if (inverseNavigationPropertyInfo == null || !navigationCandidates[inverseNavigationPropertyInfo].Type.IsAssignableFrom(entityType.ClrType)) @@ -255,7 +253,7 @@ private static bool TryRemoveIfAmbiguous( if (ambiguousInverse != null) { - if (entityType.FindSkipNavigation(navigationMemberInfo) is IConventionSkipNavigation existingSkipNavigation) + if (entityType.FindSkipNavigation(navigationMemberInfo) is { } existingSkipNavigation) { var existingSkipNavigationInverse = existingSkipNavigation.Inverse; var inverseSkipNavigation = targetEntityType.FindSkipNavigation(inverseNavigationMemberInfo); @@ -582,12 +580,11 @@ public virtual void ProcessModelFinalizing( if (ambiguousInverse != null) { Dependencies.Logger.MultipleInversePropertiesSameTargetWarning( - new[] - { + [ Tuple.Create( memberInfo, conventionEntityType.ClrType), Tuple.Create(ambiguousInverse.Value.Item1, ambiguousInverse.Value.Item2.ClrType) - }, + ], navigation, entityType.ClrType); break; diff --git a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs index 9fc72366c54..d0533f981e8 100644 --- a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs @@ -106,9 +106,8 @@ protected virtual bool ShouldDiscoverKeyProperties(IConventionEntityType entityT if (keyProperties == null) { - var candidateProperties = entityType.GetProperties().Where( - p => !p.IsImplicitlyCreated() - || !ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())); + var candidateProperties = entityType.GetProperties().Where(p => !p.IsImplicitlyCreated() + || !ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())); keyProperties = DiscoverKeyProperties(entityType, candidateProperties).ToList(); if (keyProperties.Count > 1) { @@ -196,10 +195,9 @@ public static IEnumerable DiscoverKeyProperties( if (!keyProperties.Any()) { var entityTypeName = entityType.ShortName(); - keyProperties = candidateProperties.Where( - p => p.Name.Length == entityTypeName.Length + KeySuffix.Length - && p.Name.StartsWith(entityTypeName, StringComparison.OrdinalIgnoreCase) - && p.Name.EndsWith(KeySuffix, StringComparison.OrdinalIgnoreCase)); + keyProperties = candidateProperties.Where(p => p.Name.Length == entityTypeName.Length + KeySuffix.Length + && p.Name.StartsWith(entityTypeName, StringComparison.OrdinalIgnoreCase) + && p.Name.EndsWith(KeySuffix, StringComparison.OrdinalIgnoreCase)); } // ReSharper restore PossibleMultipleEnumeration diff --git a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs index 02ee777fa7b..1ff413fda6f 100644 --- a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs +++ b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs @@ -355,12 +355,12 @@ private static IEnumerable GetAttributes(Mem { if (memberInfo == null) { - return Enumerable.Empty(); + return []; } return Attribute.IsDefined(memberInfo, typeof(TCustomAttribute), inherit: true) ? memberInfo.GetCustomAttributes(true) - : Enumerable.Empty(); + : []; } /// diff --git a/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs b/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs index d22793cb254..8fc86fa4559 100644 --- a/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs +++ b/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; diff --git a/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs b/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs index e6549e692f9..c26ec4482ae 100644 --- a/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs +++ b/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs @@ -67,11 +67,10 @@ private void ProcessNavigation(IConventionNavigationBuilder navigationBuilder) if (navigation.IsOnDependent) { - if (foreignKey.Properties.All( - p => - !p.IsNullable - || (p.IsShadowProperty() - && ConfigurationSource.Convention.Overrides(p.GetIsNullableConfigurationSource())))) + if (foreignKey.Properties.All(p => + !p.IsNullable + || (p.IsShadowProperty() + && ConfigurationSource.Convention.Overrides(p.GetIsNullableConfigurationSource())))) { foreignKey.Builder.IsRequired(true); } @@ -83,7 +82,7 @@ private void ProcessNavigation(IConventionNavigationBuilder navigationBuilder) } private bool IsNonNullable(IConventionModelBuilder modelBuilder, IConventionNavigation navigation) - => navigation.DeclaringEntityType.GetRuntimeProperties().Find(navigation.Name) is PropertyInfo propertyInfo + => navigation.DeclaringEntityType.GetRuntimeProperties().Find(navigation.Name) is { } propertyInfo && TryGetNullabilityInfo(modelBuilder, propertyInfo, out var nullabilityInfo) && nullabilityInfo.ReadState == NullabilityState.NotNull; } diff --git a/src/EFCore/Metadata/Conventions/NonNullableReferencePropertyConvention.cs b/src/EFCore/Metadata/Conventions/NonNullableReferencePropertyConvention.cs index 39ad79bfc4c..53172852849 100644 --- a/src/EFCore/Metadata/Conventions/NonNullableReferencePropertyConvention.cs +++ b/src/EFCore/Metadata/Conventions/NonNullableReferencePropertyConvention.cs @@ -29,7 +29,7 @@ public NonNullableReferencePropertyConvention(ProviderConventionSetBuilderDepend private void Process(IConventionPropertyBuilder propertyBuilder) { - if (propertyBuilder.Metadata.GetIdentifyingMemberInfo() is MemberInfo memberInfo + if (propertyBuilder.Metadata.GetIdentifyingMemberInfo() is { } memberInfo && TryGetNullabilityInfo(propertyBuilder.ModelBuilder, memberInfo, out var nullabilityInfo)) { if (nullabilityInfo.ReadState == NullabilityState.NotNull) @@ -38,7 +38,7 @@ private void Process(IConventionPropertyBuilder propertyBuilder) } // If there's an element type, this is a primitive collection; check and apply the element's nullability as well. - if (propertyBuilder.Metadata.GetElementType() is IConventionElementType elementType + if (propertyBuilder.Metadata.GetElementType() is { } elementType && nullabilityInfo is { ElementType.ReadState: NullabilityState.NotNull } or { GenericTypeArguments: [{ ReadState: NullabilityState.NotNull }] }) @@ -50,7 +50,7 @@ private void Process(IConventionPropertyBuilder propertyBuilder) private void Process(IConventionComplexPropertyBuilder propertyBuilder) { - if (propertyBuilder.Metadata.GetIdentifyingMemberInfo() is MemberInfo memberInfo + if (propertyBuilder.Metadata.GetIdentifyingMemberInfo() is { } memberInfo && TryGetNullabilityInfo(propertyBuilder.ModelBuilder, memberInfo, out var nullabilityInfo) && nullabilityInfo.ReadState == NullabilityState.NotNull) { diff --git a/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs index 325d7ca8541..5824dc1e029 100644 --- a/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs @@ -526,8 +526,8 @@ private static IReadOnlyList RemoveIncompatibleWithExisti filteredRelationshipCandidates.Add(relationshipCandidate); } else if (IsImplicitlyCreatedUnusedType(relationshipCandidate.TargetTypeBuilder.Metadata) - && filteredRelationshipCandidates.All( - c => c.TargetTypeBuilder.Metadata != relationshipCandidate.TargetTypeBuilder.Metadata)) + && filteredRelationshipCandidates.All(c + => c.TargetTypeBuilder.Metadata != relationshipCandidate.TargetTypeBuilder.Metadata)) { entityTypeBuilder.ModelBuilder .HasNoEntityType(relationshipCandidate.TargetTypeBuilder.Metadata); @@ -636,13 +636,12 @@ private static void RemoveInheritedInverseNavigations( if (inverseCandidate != null) { var relationshipsToDerivedTypes = relationshipCandidatesHierarchy - .Where( - r => r.TargetTypeBuilder != relationshipCandidate.TargetTypeBuilder - && relationshipCandidate.TargetTypeBuilder.Metadata.IsAssignableFrom(r.TargetTypeBuilder.Metadata)); + .Where(r => r.TargetTypeBuilder != relationshipCandidate.TargetTypeBuilder + && relationshipCandidate.TargetTypeBuilder.Metadata.IsAssignableFrom(r.TargetTypeBuilder.Metadata)); foreach (var relationshipToDerivedType in relationshipsToDerivedTypes) { - relationshipToDerivedType.InverseProperties.RemoveAll( - i => i.GetSimpleMemberName() == inverseCandidate.GetSimpleMemberName()); + relationshipToDerivedType.InverseProperties.RemoveAll(i + => i.GetSimpleMemberName() == inverseCandidate.GetSimpleMemberName()); if (!filteredRelationshipCandidates.Contains(relationshipToDerivedType)) { @@ -686,8 +685,8 @@ private static IReadOnlyList RemoveSingleSidedBaseNavigat filteredRelationshipCandidates.Add(relationshipCandidate); } else if (IsImplicitlyCreatedUnusedType(relationshipCandidate.TargetTypeBuilder.Metadata) - && filteredRelationshipCandidates.All( - c => c.TargetTypeBuilder.Metadata != relationshipCandidate.TargetTypeBuilder.Metadata)) + && filteredRelationshipCandidates.All(c + => c.TargetTypeBuilder.Metadata != relationshipCandidate.TargetTypeBuilder.Metadata)) { entityTypeBuilder.ModelBuilder .HasNoEntityType(relationshipCandidate.TargetTypeBuilder.Metadata); @@ -864,9 +863,8 @@ private static void RemoveExtraOwnershipInverse(IConventionEntityType entityType } } - relationshipCandidate.NavigationProperties.RemoveAll( - p => - p.GetMemberType().IsAssignableFrom(mostDerivedType) && p.GetMemberType() != mostDerivedType); + relationshipCandidate.NavigationProperties.RemoveAll(p => + p.GetMemberType().IsAssignableFrom(mostDerivedType) && p.GetMemberType() != mostDerivedType); } if (relationshipCandidate.InverseProperties.Count > 1 @@ -887,9 +885,8 @@ private static void RemoveExtraOwnershipInverse(IConventionEntityType entityType } } - relationshipCandidate.InverseProperties.RemoveAll( - p => - p.GetMemberType().IsAssignableFrom(mostDerivedType) && p.GetMemberType() != mostDerivedType); + relationshipCandidate.InverseProperties.RemoveAll(p => + p.GetMemberType().IsAssignableFrom(mostDerivedType) && p.GetMemberType() != mostDerivedType); } } @@ -931,13 +928,11 @@ private bool RemoveIfAmbiguous(IConventionEntityType entityType, RelationshipCan { Dependencies.Logger.MultipleNavigationProperties( relationshipCandidate.NavigationProperties.Count == 0 - ? new[] { new Tuple(null, targetEntityType.ClrType) } - : relationshipCandidate.NavigationProperties.Select( - n => new Tuple(n, entityType.ClrType)), + ? [new Tuple(null, targetEntityType.ClrType)] + : relationshipCandidate.NavigationProperties.Select(n => new Tuple(n, entityType.ClrType)), relationshipCandidate.InverseProperties.Count == 0 - ? new[] { new Tuple(null, targetEntityType.ClrType) } - : relationshipCandidate.InverseProperties.Select( - n => new Tuple(n, targetEntityType.ClrType))); + ? [new Tuple(null, targetEntityType.ClrType)] + : relationshipCandidate.InverseProperties.Select(n => new Tuple(n, targetEntityType.ClrType))); } foreach (var navigationProperty in relationshipCandidate.NavigationProperties.ToList()) diff --git a/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs b/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs index b061521de08..f1025d6e5c3 100644 --- a/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs +++ b/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs @@ -63,7 +63,8 @@ protected virtual RuntimeModel Create(IModel model) var elementType = property.GetElementType(); if (elementType != null) { - Check.DebugAssert(property.IsPrimitiveCollection, $"{property.Name} has an element type, but it's not a primitive collection."); + Check.DebugAssert( + property.IsPrimitiveCollection, $"{property.Name} has an element type, but it's not a primitive collection."); var runtimeElementType = Create(runtimeProperty, elementType); CreateAnnotations( elementType, runtimeElementType, static (convention, annotations, source, target, runtime) => @@ -264,12 +265,11 @@ private static RuntimeEntityType Create(IEntityType entityType, RuntimeModel mod private static ParameterBinding Create(ParameterBinding parameterBinding, RuntimeEntityType entityType) => parameterBinding.With( - parameterBinding.ConsumedProperties.Select( - property => - (entityType.FindProperty(property.Name) - ?? entityType.FindServiceProperty(property.Name) - ?? entityType.FindNavigation(property.Name) - ?? (IPropertyBase?)entityType.FindSkipNavigation(property.Name))!).ToArray()); + parameterBinding.ConsumedProperties.Select(property => + (entityType.FindProperty(property.Name) + ?? entityType.FindServiceProperty(property.Name) + ?? entityType.FindNavigation(property.Name) + ?? (IPropertyBase?)entityType.FindSkipNavigation(property.Name))!).ToArray()); private static InstantiationBinding? Create(InstantiationBinding? instantiationBinding, RuntimeEntityType entityType) => instantiationBinding?.With(instantiationBinding.ParameterBindings.Select(binding => Create(binding, entityType)).ToList()); @@ -301,13 +301,12 @@ protected virtual void ProcessEntityTypeAnnotations( if (annotations.TryGetValue(CoreAnnotationNames.QueryFilter, out var queryFilters) && queryFilters != null) { - var rewritingVisitor = new QueryRootRewritingExpressionVisitor(runtimeEntityType.Model); annotations[CoreAnnotationNames.QueryFilter] = new QueryFilterCollection( ((QueryFilterCollection)queryFilters) - .Select(x => new RuntimeQueryFilter(x.Key, (LambdaExpression)rewritingVisitor.Rewrite(x.Expression!))) - ); + .Select(x => new RuntimeQueryFilter(x.Key, (LambdaExpression)rewritingVisitor.Rewrite(x.Expression!))) + ); } } } @@ -535,7 +534,8 @@ private RuntimeComplexProperty Create(IComplexProperty complexProperty, RuntimeT var elementType = property.GetElementType(); if (elementType != null) { - Check.DebugAssert(property.IsPrimitiveCollection, $"{property.Name} has an element type, but it's not a primitive collection."); + Check.DebugAssert( + property.IsPrimitiveCollection, $"{property.Name} has an element type, but it's not a primitive collection."); var runtimeElementType = Create(runtimeProperty, elementType); CreateAnnotations( elementType, runtimeElementType, static (convention, annotations, source, target, runtime) => @@ -795,10 +795,9 @@ private RuntimeSkipNavigation Create(ISkipNavigation navigation, RuntimeEntityTy protected virtual RuntimeForeignKey GetForeignKey(IForeignKey foreignKey, RuntimeEntityType entityType) => entityType.FindDeclaredForeignKeys( entityType.FindProperties(foreignKey.Properties.Select(p => p.Name))!) - .Single( - fk => fk.PrincipalEntityType.Name == foreignKey.PrincipalEntityType.Name - && fk.PrincipalKey.Properties.Select(p => p.Name).SequenceEqual( - foreignKey.PrincipalKey.Properties.Select(p => p.Name))); + .Single(fk => fk.PrincipalEntityType.Name == foreignKey.PrincipalEntityType.Name + && fk.PrincipalKey.Properties.Select(p => p.Name).SequenceEqual( + foreignKey.PrincipalKey.Properties.Select(p => p.Name))); /// /// Gets the corresponding key in the read-optimized model. diff --git a/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs index d56941ab2d4..f7dca47a524 100644 --- a/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; diff --git a/src/EFCore/Metadata/DependencyInjectionMethodParameterBinding.cs b/src/EFCore/Metadata/DependencyInjectionMethodParameterBinding.cs index 1323b59e2df..abdb0b50133 100644 --- a/src/EFCore/Metadata/DependencyInjectionMethodParameterBinding.cs +++ b/src/EFCore/Metadata/DependencyInjectionMethodParameterBinding.cs @@ -26,8 +26,6 @@ private static readonly MethodInfo GetServiceFromPropertyMethod private static readonly MethodInfo CreateServiceMethod = typeof(DependencyInjectionMethodParameterBinding).GetTypeInfo().GetDeclaredMethod(nameof(CreateService))!; - private Func? _serviceDelegate; - /// /// Creates a new instance for the given method /// of the given service type. @@ -64,8 +62,7 @@ public override Expression BindToParameter(ParameterBindingInfo bindingInfo) var serviceInstance = bindingInfo.ServiceInstances.FirstOrDefault(e => e.Type == ServiceType); if (serviceInstance != null) { - var parameters = Method.GetParameters().Select( - (p, i) => Expression.Parameter(p.ParameterType, "param" + i)).ToArray(); + var parameters = Method.GetParameters().Select((p, i) => Expression.Parameter(p.ParameterType, "param" + i)).ToArray(); return Expression.Condition( Expression.ReferenceEqual(serviceInstance, Expression.Constant(null)), @@ -103,24 +100,24 @@ private static object CreateService( /// /// A delegate to set a CLR service property on an entity instance. /// + [field: AllowNull, MaybeNull] public override Func ServiceDelegate => NonCapturingLazyInitializer.EnsureInitialized( - ref _serviceDelegate, this, static b => + ref field, this, static b => { var materializationContextParam = Expression.Parameter(typeof(MaterializationContext)); var entityTypeParam = Expression.Parameter(typeof(IEntityType)); var entityParam = Expression.Parameter(typeof(object)); - var parameters = b.Method.GetParameters().Select( - (p, i) => Expression.Parameter(p.ParameterType, "param" + i)).ToArray(); + var parameters = b.Method.GetParameters().Select((p, i) => Expression.Parameter(p.ParameterType, "param" + i)).ToArray(); var entityType = (IEntityType)b.ConsumedProperties.First().DeclaringType; - var serviceStateProperty = entityType.GetServiceProperties().FirstOrDefault( - p => p.ParameterBinding != b && p.ParameterBinding.ServiceType == b.ServiceType); + var serviceStateProperty = entityType.GetServiceProperties() + .FirstOrDefault(p => p.ParameterBinding != b && p.ParameterBinding.ServiceType == b.ServiceType); var serviceVariable = Expression.Variable(b.ServiceType, "service"); var serviceExpression = Expression.Block( - new[] { serviceVariable }, + [serviceVariable], new List { Expression.Assign( diff --git a/src/EFCore/Metadata/IClrPropertyGetter.cs b/src/EFCore/Metadata/IClrPropertyGetter.cs index dec6fec4115..072ad80f031 100644 --- a/src/EFCore/Metadata/IClrPropertyGetter.cs +++ b/src/EFCore/Metadata/IClrPropertyGetter.cs @@ -36,7 +36,7 @@ public interface IClrPropertyGetter object? GetClrValueUsingContainingEntity(object entity, IReadOnlyList indices); /// - /// Checks whether or not the property from the containing entity instance is set to the CLR default for its type. + /// Checks whether the property from the containing entity instance is set to the CLR default for its type. /// /// The entity instance. /// if the property value is the CLR default; it is any other value. @@ -44,7 +44,7 @@ bool HasSentinelValueUsingContainingEntity(object entity) => HasSentinelValueUsingContainingEntity(entity, []); /// - /// Checks whether or not the property from the containing entity instance is set to the CLR default for its type. + /// Checks whether the property from the containing entity instance is set to the CLR default for its type. /// /// The entity instance. /// The indices corresponding to complex collections used to access the property. @@ -59,7 +59,7 @@ bool HasSentinelValueUsingContainingEntity(object entity) object? GetClrValue(object structuralObject); /// - /// Checks whether or not the property is set to the CLR default for its type. + /// Checks whether the property is set to the CLR default for its type. /// /// The entity or complex type instance. /// if the property value is the CLR default; it is any other value. diff --git a/src/EFCore/Metadata/IComplexType.cs b/src/EFCore/Metadata/IComplexType.cs index 7ce53352087..2519d190321 100644 --- a/src/EFCore/Metadata/IComplexType.cs +++ b/src/EFCore/Metadata/IComplexType.cs @@ -56,7 +56,8 @@ IEnumerable ITypeBase.GetPropertiesInHierarchy() => GetDeclaredProperties(); /// - /// Gets all properties declared on the base types and types derived from this entity type, including those on non-collection complex types. + /// Gets all properties declared on the base types and types derived from this entity type, including those on non-collection complex + /// types. /// /// The properties. IEnumerable ITypeBase.GetFlattenedPropertiesInHierarchy() diff --git a/src/EFCore/Metadata/IConstructorBindingFactory.cs b/src/EFCore/Metadata/IConstructorBindingFactory.cs index 980dfaaa73f..c4feef7f08a 100644 --- a/src/EFCore/Metadata/IConstructorBindingFactory.cs +++ b/src/EFCore/Metadata/IConstructorBindingFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata; /// diff --git a/src/EFCore/Metadata/IConventionElementType.cs b/src/EFCore/Metadata/IConventionElementType.cs index 5ff6fb71a66..b0f2663224b 100644 --- a/src/EFCore/Metadata/IConventionElementType.cs +++ b/src/EFCore/Metadata/IConventionElementType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Storage.Json; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IConventionEntityType.cs b/src/EFCore/Metadata/IConventionEntityType.cs index 366df15a396..16a7512ed65 100644 --- a/src/EFCore/Metadata/IConventionEntityType.cs +++ b/src/EFCore/Metadata/IConventionEntityType.cs @@ -236,7 +236,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas /// Indicates whether the configuration was specified using a data annotation. /// The newly created key. IConventionKey? AddKey(IConventionProperty property, bool fromDataAnnotation = false) - => AddKey(new[] { property }, fromDataAnnotation); + => AddKey([property], fromDataAnnotation); /// /// Adds a new alternate key to this entity type. @@ -261,7 +261,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas /// The property that the key is defined on. /// The key, or null if none is defined. new IConventionKey? FindKey(IReadOnlyProperty property) - => FindKey(new[] { property }); + => FindKey([property]); /// /// Gets all keys declared on the given . @@ -312,7 +312,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas IConventionKey principalKey, IConventionEntityType principalEntityType, bool fromDataAnnotation = false) - => AddForeignKey(new[] { property }, principalKey, principalEntityType, fromDataAnnotation); + => AddForeignKey([property], principalKey, principalEntityType, fromDataAnnotation); /// /// Adds a new relationship to this entity type. @@ -360,7 +360,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas /// The property to find the foreign keys on. /// The foreign keys. new IEnumerable FindForeignKeys(IReadOnlyProperty property) - => FindForeignKeys(new[] { property }); + => FindForeignKeys([property]); /// /// Gets the foreign keys defined on the given properties. Only foreign keys that are defined on exactly the specified @@ -387,7 +387,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas IReadOnlyProperty property, IReadOnlyKey principalKey, IReadOnlyEntityType principalEntityType) - => FindForeignKey(new[] { property }, principalKey, principalEntityType); + => FindForeignKey([property], principalKey, principalEntityType); /// /// Gets the foreign keys declared on this entity type using the given properties. @@ -622,7 +622,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas /// Indicates whether the configuration was specified using a data annotation. /// The newly created index. IConventionIndex? AddIndex(IConventionProperty property, bool fromDataAnnotation = false) - => AddIndex(new[] { property }, fromDataAnnotation); + => AddIndex([property], fromDataAnnotation); /// /// Adds an unnamed index to this entity type. @@ -643,7 +643,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas IConventionProperty property, string name, bool fromDataAnnotation = false) - => AddIndex(new[] { property }, name, fromDataAnnotation); + => AddIndex([property], name, fromDataAnnotation); /// /// Adds a named index to this entity type. @@ -666,7 +666,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas /// The property to find the index on. /// The index, or if none is found. new IConventionIndex? FindIndex(IReadOnlyProperty property) - => FindIndex(new[] { property }); + => FindIndex([property]); /// /// Gets the unnamed index defined on the given properties. Returns if no index is defined. @@ -808,7 +808,7 @@ public interface IConventionEntityType : IReadOnlyEntityType, IConventionTypeBas /// /// The triggers defined on this entity type. new IEnumerable GetTriggers() - => (BaseType?.GetTriggers() ?? Enumerable.Empty()).Concat(GetDeclaredTriggers()); + => (BaseType?.GetTriggers() ?? []).Concat(GetDeclaredTriggers()); /// /// Creates a new trigger with the given name on entity type. Throws an exception if a trigger with the same name exists on the same diff --git a/src/EFCore/Metadata/IConventionModel.cs b/src/EFCore/Metadata/IConventionModel.cs index 6a149ee47c3..837baf61964 100644 --- a/src/EFCore/Metadata/IConventionModel.cs +++ b/src/EFCore/Metadata/IConventionModel.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata; /// diff --git a/src/EFCore/Metadata/IConventionProperty.cs b/src/EFCore/Metadata/IConventionProperty.cs index c8f86708a73..c89367eb30d 100644 --- a/src/EFCore/Metadata/IConventionProperty.cs +++ b/src/EFCore/Metadata/IConventionProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Storage.Json; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IConventionTypeBase.cs b/src/EFCore/Metadata/IConventionTypeBase.cs index 2e20cb235ee..c79bdd3fcdf 100644 --- a/src/EFCore/Metadata/IConventionTypeBase.cs +++ b/src/EFCore/Metadata/IConventionTypeBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IEntityType.cs b/src/EFCore/Metadata/IEntityType.cs index 457dc08f44a..403dc443616 100644 --- a/src/EFCore/Metadata/IEntityType.cs +++ b/src/EFCore/Metadata/IEntityType.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata; /// @@ -97,7 +95,7 @@ public interface IEntityType : IReadOnlyEntityType, ITypeBase /// The property that the key is defined on. /// The key, or null if none is defined. new IKey? FindKey(IReadOnlyProperty property) - => FindKey(new[] { property }); + => FindKey([property]); /// /// Returns the closest entity type that is a parent of both given entity types. If one of the given entities is @@ -178,7 +176,7 @@ public interface IEntityType : IReadOnlyEntityType, ITypeBase /// The property to find the foreign keys on. /// The foreign keys. new IEnumerable FindForeignKeys(IReadOnlyProperty property) - => FindForeignKeys(new[] { property }); + => FindForeignKeys([property]); /// /// Gets the foreign keys defined on the given properties. Only foreign keys that are defined on exactly the specified @@ -204,7 +202,7 @@ public interface IEntityType : IReadOnlyEntityType, ITypeBase IReadOnlyProperty property, IReadOnlyKey principalKey, IReadOnlyEntityType principalEntityType) - => FindForeignKey(new[] { property }, principalKey, principalEntityType); + => FindForeignKey([property], principalKey, principalEntityType); /// /// Gets the foreign keys declared on the given using the given properties. @@ -395,7 +393,7 @@ IEnumerable GetNavigationsInHierarchy() /// The property to find the index on. /// The index, or if none is found. new IIndex? FindIndex(IReadOnlyProperty property) - => FindIndex(new[] { property }); + => FindIndex([property]); /// /// Gets all indexes declared on the given . @@ -529,7 +527,8 @@ IEnumerable ITypeBase.GetPropertiesInHierarchy() .SelectMany(t => t.GetDeclaredProperties()); /// - /// Gets all properties declared on the base types and types derived from this entity type, including those on non-collection complex types. + /// Gets all properties declared on the base types and types derived from this entity type, including those on non-collection complex + /// types. /// /// The properties. IEnumerable ITypeBase.GetFlattenedPropertiesInHierarchy() @@ -603,7 +602,7 @@ IEnumerable ITypeBase.GetFlattenedPropertiesInHierarchy() /// /// The triggers defined on this entity type. new IEnumerable GetTriggers() - => (BaseType?.GetTriggers() ?? Enumerable.Empty()).Concat(GetDeclaredTriggers()); + => (BaseType?.GetTriggers() ?? []).Concat(GetDeclaredTriggers()); internal const DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors diff --git a/src/EFCore/Metadata/IModel.cs b/src/EFCore/Metadata/IModel.cs index e9f67d589bc..a723b0c2da7 100644 --- a/src/EFCore/Metadata/IModel.cs +++ b/src/EFCore/Metadata/IModel.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IMutableElementType.cs b/src/EFCore/Metadata/IMutableElementType.cs index db729ca754d..0d3afc87e26 100644 --- a/src/EFCore/Metadata/IMutableElementType.cs +++ b/src/EFCore/Metadata/IMutableElementType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Storage.Json; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IMutableEntityType.cs b/src/EFCore/Metadata/IMutableEntityType.cs index af8d11a6479..ca7449a17db 100644 --- a/src/EFCore/Metadata/IMutableEntityType.cs +++ b/src/EFCore/Metadata/IMutableEntityType.cs @@ -170,7 +170,7 @@ void SetDiscriminatorMappingComplete(bool? complete) /// The property to use as an alternate key. /// The newly created key. IMutableKey AddKey(IMutableProperty property) - => AddKey(new[] { property }); + => AddKey([property]); /// /// Adds a new alternate key to this entity type. @@ -186,7 +186,7 @@ IMutableKey AddKey(IMutableProperty property) /// The property that the key is defined on. /// The key, or null if none is defined. new IMutableKey? FindKey(IReadOnlyProperty property) - => FindKey(new[] { property }); + => FindKey([property]); /// /// Gets the primary or alternate key that is defined on the given properties. @@ -243,7 +243,7 @@ IMutableForeignKey AddForeignKey( IMutableProperty property, IMutableKey principalKey, IMutableEntityType principalEntityType) - => AddForeignKey(new[] { property }, principalKey, principalEntityType); + => AddForeignKey([property], principalKey, principalEntityType); /// /// Adds a new relationship to this entity type. @@ -268,7 +268,7 @@ IMutableForeignKey AddForeignKey( /// The property to find the foreign keys on. /// The foreign keys. new IEnumerable FindForeignKeys(IReadOnlyProperty property) - => FindForeignKeys(new[] { property }); + => FindForeignKeys([property]); /// /// Gets the foreign keys defined on the given properties. Only foreign keys that are defined on exactly the specified @@ -295,7 +295,7 @@ IMutableForeignKey AddForeignKey( IReadOnlyProperty property, IReadOnlyKey principalKey, IReadOnlyEntityType principalEntityType) - => FindForeignKey(new[] { property }, principalKey, principalEntityType); + => FindForeignKey([property], principalKey, principalEntityType); /// /// Gets the foreign key for the given properties that points to a given primary or alternate key. @@ -576,7 +576,7 @@ IMutableSkipNavigation AddSkipNavigation( /// The property to be indexed. /// The newly created index. IMutableIndex AddIndex(IMutableProperty property) - => AddIndex(new[] { property }); + => AddIndex([property]); /// /// Adds an unnamed index to this entity type. @@ -592,7 +592,7 @@ IMutableIndex AddIndex(IMutableProperty property) /// The name of the index. /// The newly created index. IMutableIndex AddIndex(IMutableProperty property, string name) - => AddIndex(new[] { property }, name); + => AddIndex([property], name); /// /// Adds a named index to this entity type. @@ -608,7 +608,7 @@ IMutableIndex AddIndex(IMutableProperty property, string name) /// The property to find the index on. /// The index, or if none is found. new IMutableIndex? FindIndex(IReadOnlyProperty property) - => FindIndex(new[] { property }); + => FindIndex([property]); /// /// Gets the unnamed index defined on the given properties. Returns if no such index is defined. @@ -749,7 +749,7 @@ IMutableIndex AddIndex(IMutableProperty property, string name) /// /// The triggers defined on this entity type. new IEnumerable GetTriggers() - => (BaseType?.GetTriggers() ?? Enumerable.Empty()).Concat(GetDeclaredTriggers()); + => (BaseType?.GetTriggers() ?? []).Concat(GetDeclaredTriggers()); /// /// Creates a new trigger with the given name on entity type. Throws an exception if a trigger with the same name exists on the same diff --git a/src/EFCore/Metadata/IMutableModel.cs b/src/EFCore/Metadata/IMutableModel.cs index 350013f8eaf..18925dfaeb0 100644 --- a/src/EFCore/Metadata/IMutableModel.cs +++ b/src/EFCore/Metadata/IMutableModel.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata; /// diff --git a/src/EFCore/Metadata/IMutableProperty.cs b/src/EFCore/Metadata/IMutableProperty.cs index a0dbfc41e88..019e86cb3cc 100644 --- a/src/EFCore/Metadata/IMutableProperty.cs +++ b/src/EFCore/Metadata/IMutableProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Storage.Json; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IMutableTypeBase.cs b/src/EFCore/Metadata/IMutableTypeBase.cs index 69efecea0e5..f3e9027a662 100644 --- a/src/EFCore/Metadata/IMutableTypeBase.cs +++ b/src/EFCore/Metadata/IMutableTypeBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata; @@ -450,7 +449,7 @@ IMutableComplexProperty AddComplexIndexerProperty( /// /// The property to remove. /// The removed property, or if the property was not found. - IMutableComplexProperty? RemoveComplexProperty(IReadOnlyProperty property); + IMutableComplexProperty? RemoveComplexProperty(IReadOnlyComplexProperty property); /// /// Gets the members defined on this type and base types. diff --git a/src/EFCore/Metadata/IParameterBindingFactory.cs b/src/EFCore/Metadata/IParameterBindingFactory.cs index 5728c0d47f7..7f4e2d26028 100644 --- a/src/EFCore/Metadata/IParameterBindingFactory.cs +++ b/src/EFCore/Metadata/IParameterBindingFactory.cs @@ -21,7 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata; public interface IParameterBindingFactory { /// - /// Checks whether or not this factory can bind a parameter with the given type and name. + /// Checks whether this factory can bind a parameter with the given type and name. /// /// The parameter type. /// The parameter name. diff --git a/src/EFCore/Metadata/IProperty.cs b/src/EFCore/Metadata/IProperty.cs index 82eb39d9283..83d5bf3fb5b 100644 --- a/src/EFCore/Metadata/IProperty.cs +++ b/src/EFCore/Metadata/IProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/IPropertyBase.cs b/src/EFCore/Metadata/IPropertyBase.cs index a676e7eac12..778e17cbba1 100644 --- a/src/EFCore/Metadata/IPropertyBase.cs +++ b/src/EFCore/Metadata/IPropertyBase.cs @@ -70,5 +70,6 @@ int GetIndex() /// Gets the for this property, if it's a collection navigation or complex property. /// /// The accessor. - IClrCollectionAccessor? GetCollectionAccessor() => null; + IClrCollectionAccessor? GetCollectionAccessor() + => null; } diff --git a/src/EFCore/Metadata/IQueryFilter.cs b/src/EFCore/Metadata/IQueryFilter.cs index 65aab97ce45..1d61f971e86 100644 --- a/src/EFCore/Metadata/IQueryFilter.cs +++ b/src/EFCore/Metadata/IQueryFilter.cs @@ -1,28 +1,27 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata; /// -/// Represents a query filter in a model. +/// Represents a query filter in a model. /// public interface IQueryFilter { /// - /// The LINQ expression of the filter. + /// The LINQ expression of the filter. /// LambdaExpression? Expression { get; } /// - /// The name of the filter. + /// The name of the filter. /// string? Key { get; } /// - /// Indicates whether the query filter is anonymous. + /// Indicates whether the query filter is anonymous. /// [MemberNotNullWhen(false, nameof(Key))] - bool IsAnonymous => Key == null; + bool IsAnonymous + => Key == null; } diff --git a/src/EFCore/Metadata/IReadOnlyElementType.cs b/src/EFCore/Metadata/IReadOnlyElementType.cs index c4b4e79e4eb..cff62378ca9 100644 --- a/src/EFCore/Metadata/IReadOnlyElementType.cs +++ b/src/EFCore/Metadata/IReadOnlyElementType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.EntityFrameworkCore.Storage.Json; diff --git a/src/EFCore/Metadata/IReadOnlyEntityType.cs b/src/EFCore/Metadata/IReadOnlyEntityType.cs index 97f8d3ecec8..6a0233b3d85 100644 --- a/src/EFCore/Metadata/IReadOnlyEntityType.cs +++ b/src/EFCore/Metadata/IReadOnlyEntityType.cs @@ -43,10 +43,10 @@ public interface IReadOnlyEntityType : IReadOnlyTypeBase LambdaExpression? GetQueryFilter(); /// - /// Retrieves the query filter associated with the specified key. + /// Retrieves the query filter associated with the specified key. /// /// The key identifying the query filter to retrieve. - /// The associated with the specified key. + /// The associated with the specified key. IQueryFilter? FindDeclaredQueryFilter(string? filterKey); /// @@ -283,7 +283,7 @@ bool IsAssignableFrom(IReadOnlyEntityType derivedType) /// The property to find the foreign keys on. /// The foreign keys. IEnumerable FindForeignKeys(IReadOnlyProperty property) - => FindForeignKeys(new[] { property }); + => FindForeignKeys([property]); /// /// Gets the foreign keys defined on the given properties. Only foreign keys that are defined on exactly the specified @@ -309,7 +309,7 @@ IEnumerable FindForeignKeys(IReadOnlyProperty property) IReadOnlyProperty property, IReadOnlyKey principalKey, IReadOnlyEntityType principalEntityType) - => FindForeignKey(new[] { property }, principalKey, principalEntityType); + => FindForeignKey([property], principalKey, principalEntityType); /// /// Gets the foreign keys declared on this entity type using the given properties. @@ -548,7 +548,7 @@ bool IsInOwnershipPath(IReadOnlyEntityType targetType) /// The property to find the index on. /// The index, or if none is found. IReadOnlyIndex? FindIndex(IReadOnlyProperty property) - => FindIndex(new[] { property }); + => FindIndex([property]); /// /// Gets all indexes declared on this entity type. @@ -607,7 +607,7 @@ bool IsInOwnershipPath(IReadOnlyEntityType targetType) IEnumerable GetDerivedServiceProperties(); /// - /// Checks whether or not this entity type has any defined. + /// Checks whether this entity type has any defined. /// /// if there are any service properties defined on this entity type or base types. bool HasServiceProperties(); @@ -638,7 +638,7 @@ bool IsInOwnershipPath(IReadOnlyEntityType targetType) /// /// The triggers defined on this entity type. IEnumerable GetTriggers() - => (BaseType?.GetTriggers() ?? Enumerable.Empty()).Concat(GetDeclaredTriggers()); + => (BaseType?.GetTriggers() ?? []).Concat(GetDeclaredTriggers()); /// /// Gets the being used for navigations of this entity type. diff --git a/src/EFCore/Metadata/IReadOnlyIndex.cs b/src/EFCore/Metadata/IReadOnlyIndex.cs index 2ed08f0fde8..e353e3234f0 100644 --- a/src/EFCore/Metadata/IReadOnlyIndex.cs +++ b/src/EFCore/Metadata/IReadOnlyIndex.cs @@ -77,10 +77,9 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt builder .AppendJoin( ", ", - Properties.Select( - p => singleLine - ? p.DeclaringType.DisplayName(omitSharedType: true) + "." + p.Name - : p.Name)); + Properties.Select(p => singleLine + ? p.DeclaringType.DisplayName(omitSharedType: true) + "." + p.Name + : p.Name)); if (Name != null) { diff --git a/src/EFCore/Metadata/IReadOnlyKey.cs b/src/EFCore/Metadata/IReadOnlyKey.cs index 971cb03aea5..a80d1ec6a6d 100644 --- a/src/EFCore/Metadata/IReadOnlyKey.cs +++ b/src/EFCore/Metadata/IReadOnlyKey.cs @@ -64,10 +64,9 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt } builder.AppendJoin( - ", ", Properties.Select( - p => singleLine - ? p.DeclaringType.DisplayName(omitSharedType: true) + "." + p.Name - : p.Name)); + ", ", Properties.Select(p => singleLine + ? p.DeclaringType.DisplayName(omitSharedType: true) + "." + p.Name + : p.Name)); if (IsPrimaryKey()) { diff --git a/src/EFCore/Metadata/IReadOnlyModel.cs b/src/EFCore/Metadata/IReadOnlyModel.cs index 055f04aed15..1a81a5d13d3 100644 --- a/src/EFCore/Metadata/IReadOnlyModel.cs +++ b/src/EFCore/Metadata/IReadOnlyModel.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -180,7 +179,7 @@ IEnumerable FindLeastDerivedEntityTypes( } } - return Enumerable.Empty(); + return []; } private static int GetDerivedLevel(Type? derivedType, Dictionary derivedLevels) diff --git a/src/EFCore/Metadata/IReadOnlyNavigation.cs b/src/EFCore/Metadata/IReadOnlyNavigation.cs index 9a0cbf7a82c..5dd9bc89ae2 100644 --- a/src/EFCore/Metadata/IReadOnlyNavigation.cs +++ b/src/EFCore/Metadata/IReadOnlyNavigation.cs @@ -141,7 +141,7 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt builder.Append(" Collection"); } else if ((IsOnDependent && ForeignKey.IsRequired) - || (!IsOnDependent && ForeignKey.IsRequiredDependent)) + || (!IsOnDependent && ForeignKey.IsRequiredDependent)) { builder.Append(" Required"); } diff --git a/src/EFCore/Metadata/IReadOnlyNavigationBase.cs b/src/EFCore/Metadata/IReadOnlyNavigationBase.cs index 846b55cee61..db7ae473896 100644 --- a/src/EFCore/Metadata/IReadOnlyNavigationBase.cs +++ b/src/EFCore/Metadata/IReadOnlyNavigationBase.cs @@ -35,7 +35,7 @@ bool IsEagerLoaded => (bool?)this[CoreAnnotationNames.EagerLoaded] ?? false; /// - /// Determines whether or not this navigation should lazy-load if lazy-loading is enabled and a mechanism for lazy-loading + /// Determines whether this navigation should lazy-load if lazy-loading is enabled and a mechanism for lazy-loading /// has been configured in the model. /// /// diff --git a/src/EFCore/Metadata/IReadOnlyProperty.cs b/src/EFCore/Metadata/IReadOnlyProperty.cs index 5ffe071fa51..f8a80655c9f 100644 --- a/src/EFCore/Metadata/IReadOnlyProperty.cs +++ b/src/EFCore/Metadata/IReadOnlyProperty.cs @@ -91,13 +91,13 @@ CoreTypeMapping GetTypeMapping() int? GetScale(); /// - /// Gets a value indicating whether or not the property can persist Unicode characters. + /// Gets a value indicating whether the property can persist Unicode characters. /// /// The Unicode setting, or if none is defined. bool? IsUnicode(); /// - /// Gets a value indicating whether or not this property can be modified before the entity is + /// Gets a value indicating whether this property can be modified before the entity is /// saved to the database. /// /// @@ -115,7 +115,7 @@ CoreTypeMapping GetTypeMapping() PropertySaveBehavior GetBeforeSaveBehavior(); /// - /// Gets a value indicating whether or not this property can be modified after the entity is + /// Gets a value indicating whether this property can be modified after the entity is /// saved to the database. /// /// diff --git a/src/EFCore/Metadata/IReadOnlyPropertyBase.cs b/src/EFCore/Metadata/IReadOnlyPropertyBase.cs index 82b4b7cbce5..ad3452191f8 100644 --- a/src/EFCore/Metadata/IReadOnlyPropertyBase.cs +++ b/src/EFCore/Metadata/IReadOnlyPropertyBase.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata; /// @@ -78,8 +76,8 @@ bool IsShadowProperty() /// if the property is an indexer property, otherwise . /// bool IsIndexerProperty() - => PropertyInfo is PropertyInfo propertyInfo - && propertyInfo == DeclaringType.FindIndexerPropertyInfo(); + => PropertyInfo is not null + && PropertyInfo == DeclaringType.FindIndexerPropertyInfo(); /// /// Gets the being used for this property-like object. diff --git a/src/EFCore/Metadata/IReadOnlyTypeBase.cs b/src/EFCore/Metadata/IReadOnlyTypeBase.cs index 86fc3734eee..ca0532ee099 100644 --- a/src/EFCore/Metadata/IReadOnlyTypeBase.cs +++ b/src/EFCore/Metadata/IReadOnlyTypeBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata; diff --git a/src/EFCore/Metadata/ITypeBase.cs b/src/EFCore/Metadata/ITypeBase.cs index 903d909e292..3fd3df84d43 100644 --- a/src/EFCore/Metadata/ITypeBase.cs +++ b/src/EFCore/Metadata/ITypeBase.cs @@ -264,7 +264,8 @@ IEnumerable GetPropertiesInHierarchy() IEnumerable GetFlattenedDeclaredProperties(); /// - /// Gets all properties declared on the base types and types derived from this entity type, including those on non-collection complex types. + /// Gets all properties declared on the base types and types derived from this entity type, including those on non-collection complex + /// types. /// /// The properties. IEnumerable GetFlattenedPropertiesInHierarchy() diff --git a/src/EFCore/Metadata/ITypeMappingConfiguration.cs b/src/EFCore/Metadata/ITypeMappingConfiguration.cs index 960302d30bc..301bc7ef23d 100644 --- a/src/EFCore/Metadata/ITypeMappingConfiguration.cs +++ b/src/EFCore/Metadata/ITypeMappingConfiguration.cs @@ -38,7 +38,7 @@ public interface ITypeMappingConfiguration : IAnnotatable int? GetScale(); /// - /// Gets a value indicating whether or not the property can persist Unicode characters. + /// Gets a value indicating whether the property can persist Unicode characters. /// /// The Unicode setting, or if none is defined. bool? IsUnicode(); diff --git a/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs b/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs index 00892d2b065..7d3bcd34859 100644 --- a/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs +++ b/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs @@ -49,7 +49,7 @@ protected virtual TAccessor CreateBase(MemberInfo memberInfo) try { - return (TAccessor)boundMethod.Invoke(this, new object?[] { memberInfo, null })!; + return (TAccessor)boundMethod.Invoke(this, [memberInfo, null])!; } catch (TargetInvocationException e) when (e.InnerException != null) { diff --git a/src/EFCore/Metadata/Internal/ClrIndexedCollectionAccessorFactory.cs b/src/EFCore/Metadata/Internal/ClrIndexedCollectionAccessorFactory.cs index e3ff7f5f161..7913d43cdab 100644 --- a/src/EFCore/Metadata/Internal/ClrIndexedCollectionAccessorFactory.cs +++ b/src/EFCore/Metadata/Internal/ClrIndexedCollectionAccessorFactory.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; using System.Runtime.ExceptionServices; using JetBrains.Annotations; @@ -50,15 +51,17 @@ private ClrIndexedCollectionAccessorFactory() } var memberInfo = GetMostDerivedMemberInfo(collection); - Check.DebugAssert(memberInfo == null || memberInfo.GetMemberType() == collection.ClrType, + Check.DebugAssert( + memberInfo == null || memberInfo.GetMemberType() == collection.ClrType, $"The member '{memberInfo?.Name}' is not of the expected type '{collection.ClrType.ShortDisplayName()}'."); var propertyType = collection.IsIndexerProperty() || collection.IsShadowProperty() ? collection.ClrType : memberInfo!.GetMemberType(); var elementType = propertyType.TryGetElementType(typeof(IList<>)); - Check.DebugAssert(elementType != null, - $"The type of navigation '{collection.DeclaringType.DisplayName()}.{collection.Name}' is '{propertyType.ShortDisplayName()}' which does not implement 'IList<>'. Collection properties must implement 'IList<>' of the target type."); + Check.DebugAssert( + elementType != null, + $"The type of navigation '{collection.DeclaringType.DisplayName()}.{collection.Name}' is '{propertyType.ShortDisplayName()}' which does not implement 'IList<>'. Collection properties must implement 'IList<>' of the target type."); var boundMethod = GenericCreate.MakeGenericMethod( memberInfo?.DeclaringType ?? collection.DeclaringType.ClrType, propertyType, elementType); @@ -164,8 +167,8 @@ private static void CreateExpressions( var concreteType = collectionType; if (collectionType.IsInterface) { - if (collectionType == typeof(System.Collections.IList) || - (collectionType.IsGenericType && collectionType.GetGenericTypeDefinition() == typeof(IList<>))) + if (collectionType == typeof(IList) + || (collectionType.IsGenericType && collectionType.GetGenericTypeDefinition() == typeof(IList<>))) { concreteType = typeof(List); } @@ -224,6 +227,7 @@ private static void CreateExpressions( { memberAccessForMaterialization = Expression.Convert(memberAccessForMaterialization, typeof(TCollection)); } + index = Expression.MakeIndex(memberAccessForMaterialization, indexer, [indexParameter]); setForMaterialization = Expression.Lambda>( diff --git a/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs b/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs index 0d704e611c4..3055aefbb9d 100644 --- a/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs +++ b/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs @@ -127,8 +127,10 @@ private void CreateExpressions( readExpression = ConvertReadExpression(readExpression, hasClrSentinelValueExpression); structuralReadExpression = ConvertReadExpression(structuralReadExpression, hasStructuralSentinelValueExpression); - getClrValueUsingContainingEntityExpression = Expression.Lambda, TValue>>(readExpression, entityParameter, indicesParameter); - hasSentinelValueUsingContainingEntityExpression = Expression.Lambda, bool>>(hasClrSentinelValueExpression, entityParameter, indicesParameter); + getClrValueUsingContainingEntityExpression = + Expression.Lambda, TValue>>(readExpression, entityParameter, indicesParameter); + hasSentinelValueUsingContainingEntityExpression = Expression.Lambda, bool>>( + hasClrSentinelValueExpression, entityParameter, indicesParameter); getClrValueExpression = Expression.Lambda>(structuralReadExpression, structuralParameter); hasSentinelValueExpression = Expression.Lambda>(hasStructuralSentinelValueExpression, structuralParameter); @@ -137,7 +139,8 @@ Expression CreateReadExpression(ParameterExpression instanceParameter, Parameter { if (memberInfo.DeclaringType!.IsAssignableFrom(propertyDeclaringType)) { - return PropertyAccessorsFactory.CreateMemberAccess(propertyBase, instanceParameter, indicesParameter, memberInfo, fromDeclaringType, fromEntity: !fromDeclaringType); + return PropertyAccessorsFactory.CreateMemberAccess( + propertyBase, instanceParameter, indicesParameter, memberInfo, fromDeclaringType, fromEntity: !fromDeclaringType); } // This path handles properties that exist only on proxy types and so only exist if the instance is a proxy @@ -153,7 +156,8 @@ Expression CreateReadExpression(ParameterExpression instanceParameter, Parameter Expression.Condition( Expression.ReferenceEqual(converted, Expression.Constant(null)), Expression.Default(memberInfo.GetMemberType()), - PropertyAccessorsFactory.CreateMemberAccess(propertyBase, converted, indicesParameter, memberInfo, fromDeclaringType, fromEntity: !fromDeclaringType)) + PropertyAccessorsFactory.CreateMemberAccess( + propertyBase, converted, indicesParameter, memberInfo, fromDeclaringType, fromEntity: !fromDeclaringType)) }); } diff --git a/src/EFCore/Metadata/Internal/ClrPropertySetter.cs b/src/EFCore/Metadata/Internal/ClrPropertySetter.cs index dee794673bb..4c59556c820 100644 --- a/src/EFCore/Metadata/Internal/ClrPropertySetter.cs +++ b/src/EFCore/Metadata/Internal/ClrPropertySetter.cs @@ -37,7 +37,9 @@ public ClrPropertySetter(Func setClrValue) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public ClrPropertySetter(Action, TValue> setClrValueUsingContainingEntity, Func setClrValue) + public ClrPropertySetter( + Action, TValue> setClrValueUsingContainingEntity, + Func setClrValue) { _setClrValueUsingContainingEntity = setClrValueUsingContainingEntity; _setClrValue = setClrValue; @@ -76,11 +78,9 @@ public object SetClrValue(object instance, object? value) { return _setClrValue((TStructural)instance, (TValue)value!) ?? instance; } - else - { - // Fallback to the containing entity method with empty indices - _setClrValueUsingContainingEntity((TEntity)instance, [], (TValue)value!); - return instance; - } + + // Fallback to the containing entity method with empty indices + _setClrValueUsingContainingEntity((TEntity)instance, [], (TValue)value!); + return instance; } } diff --git a/src/EFCore/Metadata/Internal/ClrPropertySetterFactory.cs b/src/EFCore/Metadata/Internal/ClrPropertySetterFactory.cs index 24207a018e4..3e4ed948761 100644 --- a/src/EFCore/Metadata/Internal/ClrPropertySetterFactory.cs +++ b/src/EFCore/Metadata/Internal/ClrPropertySetterFactory.cs @@ -102,7 +102,8 @@ public virtual void Create( private static readonly MethodInfo GenericCreateExpression = typeof(ClrPropertySetterFactory).GetMethod(nameof(CreateExpressions), BindingFlags.Instance | BindingFlags.NonPublic)!; - private static readonly MethodInfo ComplexCollectionNullElementSetterException = typeof(CoreStrings).GetMethod(nameof(CoreStrings.ComplexCollectionNullElementSetter))!; + private static readonly MethodInfo ComplexCollectionNullElementSetterException = + typeof(CoreStrings).GetMethod(nameof(CoreStrings.ComplexCollectionNullElementSetter))!; private void CreateExpressions( MemberInfo memberInfo, @@ -111,7 +112,8 @@ private void CreateExpressions( out Expression> setterExpression) where TRoot : class { - CreateExpressionUsingContainingEntity(memberInfo, propertyBase, out setterUsingContainingEntityExpression); + CreateExpressionUsingContainingEntity( + memberInfo, propertyBase, out setterUsingContainingEntityExpression); CreateDirectExpression(memberInfo, propertyBase, out setterExpression); } @@ -142,7 +144,10 @@ private static Expression CreateConvertedValueExpression(Expression valueParamet } private static Expression CreateSimplePropertyAssignment( - MemberInfo memberInfo, IPropertyBase? propertyBase, Expression instanceParameter, Expression convertedParameter) + MemberInfo memberInfo, + IPropertyBase? propertyBase, + Expression instanceParameter, + Expression convertedParameter) => propertyBase?.IsIndexerProperty() == true ? Assign( MakeIndex( @@ -283,8 +288,9 @@ static Expression CreateMemberAssignment( } var propertyMemberInfo = propertyBase.GetMemberInfo(forMaterialization: false, forSet: true); - statements.Add(CreateSimplePropertyAssignment( - propertyMemberInfo, propertyBase, previousLevel, convertedParameter)); + statements.Add( + CreateSimplePropertyAssignment( + propertyMemberInfo, propertyBase, previousLevel, convertedParameter)); for (var i = 0; i <= chainCount - 1; i++) { diff --git a/src/EFCore/Metadata/Internal/CollectionTypeFactory.cs b/src/EFCore/Metadata/Internal/CollectionTypeFactory.cs index bfb5a5ab703..21a3e91c0b3 100644 --- a/src/EFCore/Metadata/Internal/CollectionTypeFactory.cs +++ b/src/EFCore/Metadata/Internal/CollectionTypeFactory.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; diff --git a/src/EFCore/Metadata/Internal/ComplexProperty.cs b/src/EFCore/Metadata/Internal/ComplexProperty.cs index 2e01fca8307..7587b3ccc65 100644 --- a/src/EFCore/Metadata/Internal/ComplexProperty.cs +++ b/src/EFCore/Metadata/Internal/ComplexProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -18,7 +17,6 @@ public class ComplexProperty : PropertyBase, IMutableComplexProperty, IConventio private bool? _isNullable; // Warning: Never access these fields directly as access needs to be thread-safe - private IClrCollectionAccessor? _collectionAccessor; private bool _collectionAccessorInitialized; private ConfigurationSource? _isNullableConfigurationSource; @@ -252,7 +250,7 @@ public static bool IsCompatible( /// public virtual IClrCollectionAccessor? CollectionAccessor => NonCapturingLazyInitializer.EnsureInitialized( - ref _collectionAccessor, + ref field, ref _collectionAccessorInitialized, this, static complexProperty => ClrCollectionAccessorFactory.Instance.Create(complexProperty)); diff --git a/src/EFCore/Metadata/Internal/ComplexPropertySnapshot.cs b/src/EFCore/Metadata/Internal/ComplexPropertySnapshot.cs index aa4ddd336a4..7cbb6ed258d 100644 --- a/src/EFCore/Metadata/Internal/ComplexPropertySnapshot.cs +++ b/src/EFCore/Metadata/Internal/ComplexPropertySnapshot.cs @@ -199,8 +199,7 @@ private InternalComplexPropertyBuilder MergeConfiguration(InternalComplexPropert private static ParameterBinding Create(ParameterBinding parameterBinding, ComplexType complexType) => parameterBinding.With( - parameterBinding.ConsumedProperties.Select( - property => - (IPropertyBase?)complexType.FindProperty(property.Name) - ?? complexType.FindComplexProperty(property.Name)!).ToArray()); + parameterBinding.ConsumedProperties.Select(property => + (IPropertyBase?)complexType.FindProperty(property.Name) + ?? complexType.FindComplexProperty(property.Name)!).ToArray()); } diff --git a/src/EFCore/Metadata/Internal/ComplexType.cs b/src/EFCore/Metadata/Internal/ComplexType.cs index e380d2693c6..91c29431ce0 100644 --- a/src/EFCore/Metadata/Internal/ComplexType.cs +++ b/src/EFCore/Metadata/Internal/ComplexType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -107,7 +106,8 @@ public virtual EntityType ContainingEntityType public virtual TypeBase ContainingEntryType => ComplexProperty.DeclaringType switch { - ComplexType declaringComplexType when !declaringComplexType.ComplexProperty.IsCollection => declaringComplexType.ContainingEntryType, + ComplexType declaringComplexType when !declaringComplexType.ComplexProperty.IsCollection => declaringComplexType + .ContainingEntryType, _ => ComplexProperty.DeclaringType }; @@ -395,7 +395,8 @@ public override PropertyCounts CalculateCounts() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual void SetCounts(PropertyCounts value) => _counts = value!; + public virtual void SetCounts(PropertyCounts value) + => _counts = value!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -467,9 +468,7 @@ public override string ToString() /// doing so can result in application failures when updating to a new Entity Framework Core release. /// IMutableComplexType? IMutableComplexType.BaseType - { - get => BaseType; - } + => BaseType; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs b/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs index 1b79e4b1f7d..0e54232dfda 100644 --- a/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs +++ b/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Internal; /// @@ -182,11 +180,10 @@ private void GetBindings( { var constructorErrors = bindingFailures.SelectMany(f => f) .GroupBy(f => (ConstructorInfo)f.Member) - .Select( - x => " " - + CoreStrings.ConstructorBindingFailed( - string.Join("', '", x.Select(f => f.Name)), - $"{type.DisplayName()}({string.Join(", ", ConstructConstructor(x))})") + .Select(x => " " + + CoreStrings.ConstructorBindingFailed( + string.Join("', '", x.Select(f => f.Name)), + $"{type.DisplayName()}({string.Join(", ", ConstructConstructor(x))})") ); throw new InvalidOperationException( diff --git a/src/EFCore/Metadata/Internal/ElementType.cs b/src/EFCore/Metadata/Internal/ElementType.cs index 0b05492bdf9..047bb8ec844 100644 --- a/src/EFCore/Metadata/Internal/ElementType.cs +++ b/src/EFCore/Metadata/Internal/ElementType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Storage.Json; diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs index 166d152c306..d427c0ba49e 100644 --- a/src/EFCore/Metadata/Internal/EntityType.cs +++ b/src/EFCore/Metadata/Internal/EntityType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -53,7 +52,6 @@ private readonly SortedDictionary _triggers // Warning: Never access these fields directly as access needs to be thread-safe private PropertyCounts? _counts; - private Func? _relationshipSnapshotFactory; private IProperty[]? _foreignKeyProperties; private IProperty[]? _valueGeneratingProperties; @@ -257,6 +255,7 @@ public virtual EntityType? Owner /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + // ReSharper disable once MemberHidesInterfaceMemberWithDefaultImplementation private string DisplayName() => ((IReadOnlyEntityType)this).DisplayName(); @@ -478,7 +477,7 @@ private bool InheritsFrom(EntityType entityType) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - new public virtual EntityType GetRootType() + public new virtual EntityType GetRootType() => (EntityType)((IReadOnlyTypeBase)this).GetRootType(); /// @@ -706,7 +705,7 @@ private void UpdatePrimaryKeyConfigurationSource(ConfigurationSource configurati /// public virtual Key? AddKey(Property property, ConfigurationSource configurationSource) => AddKey( - new[] { property }, configurationSource); + [property], configurationSource); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -788,7 +787,7 @@ private void UpdatePrimaryKeyConfigurationSource(ConfigurationSource configurati /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual Key? FindKey(IReadOnlyProperty property) - => FindKey(new[] { property }); + => FindKey([property]); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -931,7 +930,7 @@ public virtual IEnumerable GetKeys() ConfigurationSource? componentConfigurationSource, ConfigurationSource configurationSource) => AddForeignKey( - new[] { property }, principalKey, principalEntityType, componentConfigurationSource, configurationSource); + [property], principalKey, principalEntityType, componentConfigurationSource, configurationSource); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1050,7 +1049,7 @@ public virtual void OnForeignKeyUpdated(ForeignKey foreignKey) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual IEnumerable FindForeignKeys(IReadOnlyProperty property) - => FindForeignKeys(new[] { property }); + => FindForeignKeys([property]); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1081,7 +1080,7 @@ public virtual IEnumerable FindForeignKeys(IReadOnlyList FindForeignKey( - new[] { property }, principalKey, principalEntityType); + [property], principalKey, principalEntityType); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1158,7 +1157,7 @@ public virtual IEnumerable GetDeclaredForeignKeys() /// public virtual IEnumerable GetDerivedForeignKeys() => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et._foreignKeys); /// @@ -1185,7 +1184,7 @@ public virtual IEnumerable FindDeclaredForeignKeys(IReadOnlyList() + ? [] : _foreignKeys.Where(fk => PropertyListComparer.Instance.Equals(fk.Properties, properties)); } @@ -1230,7 +1229,7 @@ public virtual IEnumerable FindDeclaredForeignKeys(IReadOnlyList FindDerivedForeignKeys( IReadOnlyList properties) => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.FindDeclaredForeignKeys(properties)); /// @@ -1244,7 +1243,7 @@ public virtual IEnumerable FindDerivedForeignKeys( IReadOnlyKey principalKey, IReadOnlyEntityType principalEntityType) => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredForeignKey(properties, principalKey, principalEntityType)) .Where(fk => fk != null); @@ -1549,7 +1548,7 @@ public virtual IEnumerable GetDeclaredNavigations() /// public virtual IEnumerable GetDerivedNavigations() => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredNavigations()); /// @@ -1563,7 +1562,7 @@ public virtual IEnumerable FindDerivedNavigations(string name) Check.NotNull(name); return DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredNavigation(name)).Where(n => n != null); } @@ -1738,7 +1737,7 @@ public virtual IEnumerable GetDeclaredSkipNavigations() /// public virtual IEnumerable GetDerivedSkipNavigations() => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredSkipNavigations()); /// @@ -1752,7 +1751,7 @@ public virtual IEnumerable FindDerivedSkipNavigations(string nam Check.NotNull(name); return DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredSkipNavigation(name)).Where(n => n != null); } @@ -1825,7 +1824,7 @@ public virtual IEnumerable FindSkipNavigationsInHierarchy(string var removed = _skipNavigations.Remove(navigation.Name); Check.DebugAssert(removed, "Expected the navigation to be removed"); - removed = navigation.ForeignKey is not ForeignKey foreignKey + removed = navigation.ForeignKey is not { } foreignKey || foreignKey.ReferencingSkipNavigations!.Remove(navigation); Check.DebugAssert(removed, "removed is false"); @@ -1880,7 +1879,7 @@ public virtual IEnumerable GetDeclaredReferencingSkipNavigations /// public virtual IEnumerable GetDerivedReferencingSkipNavigations() => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredReferencingSkipNavigations()); private SortedSet? _declaredReferencingSkipNavigations; @@ -1898,7 +1897,7 @@ public virtual IEnumerable GetDerivedReferencingSkipNavigations( public virtual Index? AddIndex( Property property, ConfigurationSource configurationSource) - => AddIndex(new[] { property }, configurationSource); + => AddIndex([property], configurationSource); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1910,7 +1909,7 @@ public virtual IEnumerable GetDerivedReferencingSkipNavigations( Property property, string name, ConfigurationSource configurationSource) - => AddIndex(new[] { property }, name, configurationSource); + => AddIndex([property], name, configurationSource); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -2023,7 +2022,7 @@ private static void UpdatePropertyIndexes(IReadOnlyList properties, In /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual Index? FindIndex(IReadOnlyProperty property) - => FindIndex(new[] { property }); + => FindIndex([property]); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -2071,7 +2070,7 @@ public virtual IEnumerable GetDeclaredIndexes() /// public virtual IEnumerable GetDerivedIndexes() => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredIndexes()); /// @@ -2100,7 +2099,7 @@ public virtual IEnumerable GetDerivedIndexes() /// public virtual IEnumerable FindDerivedIndexes(IReadOnlyList properties) => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredIndex(properties)).Where(i => i != null); @@ -2112,7 +2111,7 @@ public virtual IEnumerable FindDerivedIndexes(IReadOnlyList public virtual IEnumerable FindDerivedIndexes(string name) => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredIndex(Check.NotEmpty(name))) .Where(i => i != null); @@ -2240,13 +2239,13 @@ public virtual IEnumerable GetIndexes() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override PropertyCounts CalculateCounts() => - NonCapturingLazyInitializer.EnsureInitialized( - ref _counts, this, static entityType => - { - entityType.EnsureReadOnly(); - return EntityTypeExtensions.CalculateCounts(entityType); - }); + public override PropertyCounts CalculateCounts() + => NonCapturingLazyInitializer.EnsureInitialized( + ref _counts, this, static entityType => + { + entityType.EnsureReadOnly(); + return EntityTypeExtensions.CalculateCounts(entityType); + }); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -2263,9 +2262,10 @@ public override IEnumerable GetSnapshottableMembers() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func RelationshipSnapshotFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _relationshipSnapshotFactory, this, + ref field, this, static entityType => { entityType.EnsureReadOnly(); @@ -2386,7 +2386,7 @@ public virtual IEnumerable FindDerivedServiceProperties(string Check.NotNull(propertyName); return DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredServiceProperty(propertyName)) .Where(p => p != null); @@ -2436,7 +2436,7 @@ public virtual IEnumerable FindServicePropertiesInHierarchy(str /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual ServiceProperty RemoveServiceProperty(ServiceProperty property) + public virtual ServiceProperty? RemoveServiceProperty(ServiceProperty property) { Check.NotNull(property); Check.DebugAssert(IsInModel, "The entity type has been removed from the model"); @@ -2452,7 +2452,10 @@ public virtual ServiceProperty RemoveServiceProperty(ServiceProperty property) } var removed = _serviceProperties.Remove(property.Name); - Check.DebugAssert(removed, "removed is false"); + if (!removed) + { + return null; + } property.SetRemovedFromModel(); @@ -2498,7 +2501,7 @@ public virtual IEnumerable GetDeclaredServiceProperties() /// public virtual IEnumerable GetDerivedServiceProperties() => DirectlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredServiceProperties()); #endregion @@ -2605,7 +2608,7 @@ public virtual IEnumerable GetDeclaredTriggers() if (_data == null || _data.Count == 0) { - return Enumerable.Empty>(); + return []; } List? propertiesList = null; @@ -2765,18 +2768,6 @@ public virtual PropertyAccessMode GetNavigationAccessMode() => (PropertyAccessMode?)this[CoreAnnotationNames.NavigationAccessMode] ?? GetPropertyAccessMode(); - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - public virtual PropertyAccessMode? SetNavigationAccessMode( - PropertyAccessMode? propertyAccessMode, - ConfigurationSource configurationSource) - => (PropertyAccessMode?)SetOrRemoveAnnotation( - CoreAnnotationNames.NavigationAccessMode, propertyAccessMode, configurationSource)?.Value; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -2801,8 +2792,8 @@ public virtual PropertyAccessMode GetNavigationAccessMode() queryFilters = null; } - if (FindAnnotation(CoreAnnotationNames.QueryFilter)?.Value != queryFilters) { - + if (FindAnnotation(CoreAnnotationNames.QueryFilter)?.Value != queryFilters) + { SetOrRemoveAnnotation(CoreAnnotationNames.QueryFilter, queryFilters, configSource); } @@ -4626,13 +4617,12 @@ public virtual void Attach(InternalEntityTypeBuilder entityTypeBuilder) private static ParameterBinding Create(ParameterBinding parameterBinding, EntityType entityType) => parameterBinding.With( - parameterBinding.ConsumedProperties.Select( - property => - (entityType.FindProperty(property.Name) - ?? entityType.FindServiceProperty(property.Name) - ?? entityType.FindComplexProperty(property.Name) - ?? entityType.FindNavigation(property.Name) - ?? (IPropertyBase?)entityType.FindSkipNavigation(property.Name))!).ToArray()); + parameterBinding.ConsumedProperties.Select(property => + (entityType.FindProperty(property.Name) + ?? entityType.FindServiceProperty(property.Name) + ?? entityType.FindComplexProperty(property.Name) + ?? entityType.FindNavigation(property.Name) + ?? (IPropertyBase?)entityType.FindSkipNavigation(property.Name))!).ToArray()); } /// diff --git a/src/EFCore/Metadata/Internal/EntityTypeExtensions.cs b/src/EFCore/Metadata/Internal/EntityTypeExtensions.cs index e2ff487c5d5..a3479000238 100644 --- a/src/EFCore/Metadata/Internal/EntityTypeExtensions.cs +++ b/src/EFCore/Metadata/Internal/EntityTypeExtensions.cs @@ -173,7 +173,7 @@ public static PropertyCounts CalculateCounts(this IRuntimeEntityType entityType) var isNotifying = entityType.GetChangeTrackingStrategy() != ChangeTrackingStrategy.Snapshot; foreach (IRuntimeNavigationBase navigation in entityType.GetDeclaredNavigations() - .Union(entityType.GetDeclaredSkipNavigations())) + .Union(entityType.GetDeclaredSkipNavigations())) { var indexes = new PropertyIndexes( index: navigationIndex++, @@ -295,15 +295,16 @@ private static void CalculateCounts( if (complexProperty.IsCollection) { - ((IRuntimeComplexType)complexProperty.ComplexType).SetCounts(new PropertyCounts( - propertyIndex, - navigationCount: 0, - complexPropertyIndex, - complexCollectionIndex, - originalValueIndex, - shadowIndex, - relationshipIndex, - storeGenerationIndex)); + ((IRuntimeComplexType)complexProperty.ComplexType).SetCounts( + new PropertyCounts( + propertyIndex, + navigationCount: 0, + complexPropertyIndex, + complexCollectionIndex, + originalValueIndex, + shadowIndex, + relationshipIndex, + storeGenerationIndex)); propertyIndex = parentPropertyIndex; complexPropertyIndex = parentComplexPropertyIndex; diff --git a/src/EFCore/Metadata/Internal/ForeignKey.cs b/src/EFCore/Metadata/Internal/ForeignKey.cs index c31b755ff98..a57d6a2ab5d 100644 --- a/src/EFCore/Metadata/Internal/ForeignKey.cs +++ b/src/EFCore/Metadata/Internal/ForeignKey.cs @@ -32,8 +32,6 @@ public class ForeignKey : ConventionAnnotatable, IMutableForeignKey, IConvention private ConfigurationSource? _isOwnershipConfigurationSource; private ConfigurationSource? _dependentToPrincipalConfigurationSource; private ConfigurationSource? _principalToDependentConfigurationSource; - private IDependentKeyValueFactory? _dependentKeyValueFactory; - private Func? _dependentsMapFactory; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -945,23 +943,24 @@ public virtual EntityType ResolveOtherEntityType(EntityType entityType) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual IDependentKeyValueFactory DependentKeyValueFactory { get { - if (_dependentKeyValueFactory == null) + if (field == null) { EnsureReadOnly(); } - return _dependentKeyValueFactory!; + return field!; } set { EnsureReadOnly(); - _dependentKeyValueFactory = value; + field = value; } } @@ -972,23 +971,24 @@ public virtual IDependentKeyValueFactory DependentKeyValueFactory /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func DependentsMapFactory { get { - if (_dependentsMapFactory == null) + if (field == null) { EnsureReadOnly(); } - return _dependentsMapFactory!; + return field!; } set { EnsureReadOnly(); - _dependentsMapFactory = value; + field = value; } } diff --git a/src/EFCore/Metadata/Internal/InternalComplexPropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalComplexPropertyBuilder.cs index 00248bc11ec..d67479eead0 100644 --- a/src/EFCore/Metadata/Internal/InternalComplexPropertyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalComplexPropertyBuilder.cs @@ -143,7 +143,8 @@ public virtual InternalComplexTypeBuilder ComplexTypeBuilder } var detachedProperties = InternalTypeBaseBuilder.DetachProperties(complexType.GetDeclaredProperties().ToList()); - var detachedNestedComplexProperties = InternalTypeBaseBuilder.DetachProperties(complexType.GetDeclaredComplexProperties().ToList()) ?? []; + var detachedNestedComplexProperties = + InternalTypeBaseBuilder.DetachProperties(complexType.GetDeclaredComplexProperties().ToList()) ?? []; var snapshot = new ComplexPropertySnapshot( complexProperty.Builder, diff --git a/src/EFCore/Metadata/Internal/InternalComplexTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalComplexTypeBuilder.cs index fc85289524e..aa03bb7c0ff 100644 --- a/src/EFCore/Metadata/Internal/InternalComplexTypeBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalComplexTypeBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -54,9 +53,8 @@ protected override bool CanAddProperty( || propertyType != null || Metadata.GetRuntimeProperties().ContainsKey(propertyName)) && Metadata.FindComplexPropertiesInHierarchy(propertyName) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -77,9 +75,8 @@ public override bool CanAddComplexProperty( || propertyType != null || Metadata.GetRuntimeProperties().ContainsKey(propertyName)) && Metadata.FindPropertiesInHierarchy(propertyName) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -714,7 +711,10 @@ IConventionComplexTypeBuilder IConventionComplexTypeBuilder.RemoveUnusedImplicit /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - IConventionComplexTypeDiscriminatorBuilder? IConventionComplexTypeBuilder.HasDiscriminator(string name, Type type, bool fromDataAnnotation) + IConventionComplexTypeDiscriminatorBuilder? IConventionComplexTypeBuilder.HasDiscriminator( + string name, + Type type, + bool fromDataAnnotation) => HasDiscriminator( Check.NotEmpty(name), Check.NotNull(type), fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); @@ -726,7 +726,9 @@ IConventionComplexTypeBuilder IConventionComplexTypeBuilder.RemoveUnusedImplicit /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - IConventionComplexTypeDiscriminatorBuilder? IConventionComplexTypeBuilder.HasDiscriminator(MemberInfo memberInfo, bool fromDataAnnotation) + IConventionComplexTypeDiscriminatorBuilder? IConventionComplexTypeBuilder.HasDiscriminator( + MemberInfo memberInfo, + bool fromDataAnnotation) => HasDiscriminator( memberInfo, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); diff --git a/src/EFCore/Metadata/Internal/InternalElementTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalElementTypeBuilder.cs index a05183517b2..4a318400df5 100644 --- a/src/EFCore/Metadata/Internal/InternalElementTypeBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalElementTypeBuilder.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Internal; /// diff --git a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs index 74779ba16e8..72f06816d57 100644 --- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal; @@ -602,9 +601,8 @@ protected override bool CanAddProperty( .Concat(Metadata.FindComplexPropertiesInHierarchy(propertyName)) .Concat(Metadata.FindNavigationsInHierarchy(propertyName)) .Concat(Metadata.FindSkipNavigationsInHierarchy(propertyName)) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -700,7 +698,7 @@ public virtual IMutableNavigationBase Navigation(string navigationName) } } - Check.DebugAssert(configurationSource is not null, "configurationSource is not null"); + Check.DebugAssert(configurationSource is not null); using (ModelBuilder.Metadata.DelayConventions()) { @@ -763,13 +761,11 @@ private bool CanAddServiceProperty(MemberInfo memberInfo, ConfigurationSource co .Concat(Metadata.FindComplexPropertiesInHierarchy(propertyName)) .Concat(Metadata.FindNavigationsInHierarchy(propertyName)) .Concat(Metadata.FindSkipNavigationsInHierarchy(propertyName)) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit) - && Metadata.FindServicePropertiesInHierarchy(propertyName).All( - m => (configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit) - || memberInfo.IsOverriddenBy(m.GetIdentifyingMemberInfo())); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit) + && Metadata.FindServicePropertiesInHierarchy(propertyName).All(m => (configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit) + || memberInfo.IsOverriddenBy(m.GetIdentifyingMemberInfo())); } private static InternalServicePropertyBuilder? DetachServiceProperty(ServiceProperty? serviceProperty) @@ -835,9 +831,8 @@ public override bool CanAddComplexProperty( .Concat(Metadata.FindServicePropertiesInHierarchy(propertyName)) .Concat(Metadata.FindNavigationsInHierarchy(propertyName)) .Concat(Metadata.FindSkipNavigationsInHierarchy(propertyName)) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -875,14 +870,13 @@ public virtual bool CanAddNavigation( .Concat(Metadata.FindServicePropertiesInHierarchy(navigationName)) .Concat(Metadata.FindComplexPropertiesInHierarchy(navigationName)) .Concat(Metadata.FindSkipNavigationsInHierarchy(navigationName)) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit); private bool CanBeNavigation(Type type, ConfigurationSource configurationSource) => configurationSource == ConfigurationSource.Explicit || ModelBuilder.Metadata.Configuration?.GetConfigurationType(type).IsEntityType() != false - && (type.TryGetSequenceType() is not Type sequenceType + && (type.TryGetSequenceType() is not { } sequenceType || ModelBuilder.Metadata.Configuration?.GetConfigurationType(sequenceType).IsEntityType() != false); /// @@ -912,9 +906,8 @@ private bool CanAddSkipNavigation( .Concat(Metadata.FindComplexPropertiesInHierarchy(skipNavigationName)) .Concat(Metadata.FindServicePropertiesInHierarchy(skipNavigationName)) .Concat(Metadata.FindNavigationsInHierarchy(skipNavigationName)) - .All( - m => configurationSource.Overrides(m.GetConfigurationSource()) - && m.GetConfigurationSource() != ConfigurationSource.Explicit); + .All(m => configurationSource.Overrides(m.GetConfigurationSource()) + && m.GetConfigurationSource() != ConfigurationSource.Explicit); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1813,9 +1806,8 @@ public virtual bool CanSetBaseType(EntityType? baseEntityType, ConfigurationSour } var configurationSourceForRemoval = ConfigurationSource.DataAnnotation.Max(configurationSource); - if (Metadata.GetDeclaredKeys().Any( - k => !configurationSourceForRemoval.Overrides(k.GetConfigurationSource()) - && k.Properties.Any(p => baseEntityType.FindProperty(p.Name) == null)) + if (Metadata.GetDeclaredKeys().Any(k => !configurationSourceForRemoval.Overrides(k.GetConfigurationSource()) + && k.Properties.Any(p => baseEntityType.FindProperty(p.Name) == null)) || (Metadata.IsKeyless && !configurationSource.Overrides(Metadata.GetIsKeylessConfigurationSource()))) { return false; @@ -3016,7 +3008,7 @@ public static InternalIndexBuilder DetachIndex(Index indexToDetach) if (newRelationship == null) { - if (relationship?.Metadata.IsInModel == true) + if (relationship.Metadata.IsInModel) { relationship.Metadata.DeclaringEntityType.Builder.HasNoRelationship(relationship.Metadata, configurationSource); } @@ -3171,9 +3163,7 @@ public static InternalIndexBuilder DetachIndex(Index indexToDetach) var ownership = Metadata.FindOwnership(); var existingDerivedNavigations = Metadata.FindDerivedNavigations(navigation.Name!) .Where(n => n.ForeignKey.IsOwnership).ToList(); - if (existingDerivedNavigations.Count == 1 - && existingDerivedNavigations[0].ForeignKey.DeclaringEntityType is EntityType existingOwnedType - && !existingOwnedType.HasSharedClrType) + if (existingDerivedNavigations is [{ ForeignKey.DeclaringEntityType: { HasSharedClrType: false } existingOwnedType }]) { ownedEntityTypeBuilder = existingOwnedType.Builder; ownedEntityTypeBuilder.HasNoRelationship(existingDerivedNavigations[0].ForeignKey, configurationSource); @@ -3480,15 +3470,13 @@ private bool RemoveNonOwnershipRelationships(ForeignKey? futureOwnership, Config var ownership = Metadata.FindOwnership() ?? futureOwnership; var incompatibleRelationships = Metadata.GetDerivedTypesInclusive().Cast() .SelectMany(t => t.GetDeclaredForeignKeys()) - .Where( - fk => fk is { IsOwnership: false, PrincipalToDependent: not null } - && !Contains(ownership, fk)) + .Where(fk => fk is { IsOwnership: false, PrincipalToDependent: not null } + && !Contains(ownership, fk)) .Concat( Metadata.GetDerivedTypesInclusive().Cast() .SelectMany(t => t.GetDeclaredReferencingForeignKeys()) - .Where( - fk => !fk.IsOwnership - && !Contains(fk.DeclaringEntityType.FindOwnership(), fk))) + .Where(fk => !fk.IsOwnership + && !Contains(fk.DeclaringEntityType.FindOwnership(), fk))) .ToList(); if (incompatibleRelationships.Any(fk => !configurationSource.Overrides(fk.GetConfigurationSource()))) @@ -3908,7 +3896,7 @@ private static bool Contains(IReadOnlyForeignKey? inheritedFk, IReadOnlyForeignK if (principalKey == null) { var principalKeyProperties = principalBaseEntityTypeBuilder.TryCreateUniqueProperties( - 1, null, new[] { typeof(int) }, new[] { "TempId" }, isRequired: true, baseName: "").Item2; + 1, null, [typeof(int)], ["TempId"], isRequired: true, baseName: "").Item2; if (principalKeyProperties == null) { @@ -4141,7 +4129,7 @@ private static bool Contains(IReadOnlyForeignKey? inheritedFk, IReadOnlyForeignK if (navigationsToDetach != null) { - detachedNavigations = new List<(InternalSkipNavigationBuilder, InternalSkipNavigationBuilder)>(); + detachedNavigations = []; foreach (var navigationToDetach in navigationsToDetach) { var inverse = navigationToDetach.Inverse; @@ -5311,7 +5299,10 @@ bool IConventionEntityTypeBuilder.CanSetQueryFilter(LambdaExpression? filter, bo /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - IConventionEntityTypeBuilder? IConventionEntityTypeBuilder.HasQueryFilter(string filterKey, LambdaExpression? filter, bool fromDataAnnotation) + IConventionEntityTypeBuilder? IConventionEntityTypeBuilder.HasQueryFilter( + string filterKey, + LambdaExpression? filter, + bool fromDataAnnotation) => HasQueryFilter(new QueryFilter(filterKey, filter, fromDataAnnotation)); /// diff --git a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs index 9e6bb9ebdcb..667928d687a 100644 --- a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs @@ -642,8 +642,8 @@ private bool CanSetNavigations( } conflictingNavigationsFound = compatibleRelationship != null - || resolvableRelationships.Any( - r => (r.Resolution & (Resolution.ResetToDependent | Resolution.ResetToPrincipal | Resolution.Remove)) != 0); + || resolvableRelationships.Any(r + => (r.Resolution & (Resolution.ResetToDependent | Resolution.ResetToPrincipal | Resolution.Remove)) != 0); if (shouldBeUnique == null && (Metadata.IsUnique || configurationSource.OverridesStrictly(Metadata.GetIsUniqueConfigurationSource())) @@ -1515,13 +1515,12 @@ public virtual bool CanInvert( var relationshipBuilder = this; using var batch = Metadata.DeclaringEntityType.Model.DelayConventions(); - var temporaryProperties = Metadata.Properties.Where( - p => (p.IsShadowProperty() || p.DeclaringType.IsPropertyBag && p.IsIndexerProperty()) - && ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())).ToList(); + var temporaryProperties = Metadata.Properties.Where(p + => (p.IsShadowProperty() || p.DeclaringType.IsPropertyBag && p.IsIndexerProperty()) + && ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())).ToList(); - var keysToDetach = temporaryProperties.SelectMany( - p => p.GetContainingKeys() - .Where(k => ConfigurationSource.Convention.Overrides(k.GetConfigurationSource()))) + var keysToDetach = temporaryProperties.SelectMany(p => p.GetContainingKeys() + .Where(k => ConfigurationSource.Convention.Overrides(k.GetConfigurationSource()))) .Distinct().ToList(); List? detachedRelationships = null; @@ -1725,8 +1724,7 @@ public virtual bool CanInvert( public virtual bool CanSetForeignKey(IReadOnlyList? propertyNames, ConfigurationSource? configurationSource) { if (propertyNames is not null - && ((IReadOnlyEntityType)Metadata.DeclaringEntityType).FindProperties(propertyNames) is IReadOnlyList - properties) + && ((IReadOnlyEntityType)Metadata.DeclaringEntityType).FindProperties(propertyNames) is { } properties) { return CanSetForeignKey( properties, @@ -1938,8 +1936,7 @@ private bool CanSetForeignKey( public virtual bool CanSetPrincipalKey(IReadOnlyList? propertyNames, ConfigurationSource? configurationSource) { if (propertyNames is not null - && ((IReadOnlyEntityType)Metadata.PrincipalEntityType).FindProperties(propertyNames) is IReadOnlyList - properties) + && ((IReadOnlyEntityType)Metadata.PrincipalEntityType).FindProperties(propertyNames) is { } properties) { return CanSetPrincipalKey( properties, @@ -2001,9 +1998,8 @@ private bool CanSetPrincipalKey( } if (Metadata.GetPropertiesConfigurationSource().Overrides(ConfigurationSource.DataAnnotation) - && Metadata.Properties.All( - p => ConfigurationSource.Convention.Overrides(p.GetTypeConfigurationSource()) - && (p.IsShadowProperty() || p.IsIndexerProperty()))) + && Metadata.Properties.All(p => ConfigurationSource.Convention.Overrides(p.GetTypeConfigurationSource()) + && (p.IsShadowProperty() || p.IsIndexerProperty()))) { oldNameDependentProperties = Metadata.Properties; } @@ -2776,17 +2772,15 @@ private static InternalForeignKeyBuilder MergeFacetsFrom(Navigation newNavigatio // This workaround prevents the properties to be cleaned away before the new FK is created, // this should be replaced with reference counting // Issue #15898 - var temporaryProperties = dependentProperties?.Where( - p => p.GetConfigurationSource() == ConfigurationSource.Convention - && ((IConventionProperty)p).IsImplicitlyCreated()).ToList(); + var temporaryProperties = dependentProperties?.Where(p => p.GetConfigurationSource() == ConfigurationSource.Convention + && ((IConventionProperty)p).IsImplicitlyCreated()).ToList(); var tempIndex = temporaryProperties?.Count > 0 && dependentEntityType.FindIndex(temporaryProperties) == null ? dependentEntityType.Builder.HasIndex(temporaryProperties, ConfigurationSource.Convention)!.Metadata : null; - var temporaryKeyProperties = principalProperties?.Where( - p => p.GetConfigurationSource() == ConfigurationSource.Convention - && ((IConventionProperty)p).IsImplicitlyCreated()).ToList(); + var temporaryKeyProperties = principalProperties?.Where(p => p.GetConfigurationSource() == ConfigurationSource.Convention + && ((IConventionProperty)p).IsImplicitlyCreated()).ToList(); var keyTempIndex = temporaryKeyProperties?.Count > 0 && principalEntityType.FindIndex(temporaryKeyProperties) == null ? principalEntityType.Builder.HasIndex(temporaryKeyProperties, ConfigurationSource.Convention)!.Metadata @@ -2896,9 +2890,8 @@ private static InternalForeignKeyBuilder MergeFacetsFrom(Navigation newNavigatio principalEntityType, dependentEntityType, shouldThrow: false) - && dependentProperties.All( - p => ConfigurationSource.Convention.Overrides(p.GetTypeConfigurationSource()) - && (p.IsShadowProperty() || p.IsIndexerProperty())))) + && dependentProperties.All(p => ConfigurationSource.Convention.Overrides(p.GetTypeConfigurationSource()) + && (p.IsShadowProperty() || p.IsIndexerProperty())))) { dependentProperties = (oldNameDependentProperties ?? dependentProperties)!; if (principalKey.Properties.Count == dependentProperties.Count) @@ -2983,7 +2976,7 @@ private static InternalForeignKeyBuilder MergeFacetsFrom(Navigation newNavigatio { existingRelationshipInverted = null; conflictingRelationshipsFound = false; - resolvableRelationships = new List<(InternalForeignKeyBuilder, bool, Resolution, bool)>(); + resolvableRelationships = []; var matchingRelationships = FindRelationships( principalEntityType, diff --git a/src/EFCore/Metadata/Internal/InternalModelBuilder.cs b/src/EFCore/Metadata/Internal/InternalModelBuilder.cs index 9da4bd271ae..c7bf0ae751e 100644 --- a/src/EFCore/Metadata/Internal/InternalModelBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalModelBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -429,9 +428,8 @@ public virtual bool CanHaveEntity( continue; } - var ownershipCandidates = entityType.GetForeignKeys().Where( - fk => fk.PrincipalToDependent != null - && !fk.PrincipalEntityType.IsInOwnershipPath(type)).ToList(); + var ownershipCandidates = entityType.GetForeignKeys().Where(fk => fk.PrincipalToDependent != null + && !fk.PrincipalEntityType.IsInOwnershipPath(type)).ToList(); if (ownershipCandidates.Count >= 1) { if (ownershipCandidates[0].Builder.IsOwnership(true, configurationSource) == null) diff --git a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs index 2b5e128dbbb..79502c4b441 100644 --- a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.EntityFrameworkCore.Internal; diff --git a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs index a5bef15398a..a378f507888 100644 --- a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs @@ -186,7 +186,7 @@ public virtual bool CanSetInverse( { entityTypeBuilder = Metadata.DeclaringEntityType.Builder; } - else if (Metadata.DeclaringEntityType.Model.FindEntityType(Metadata.DeclaringEntityType.Name) is EntityType entityType) + else if (Metadata.DeclaringEntityType.Model.FindEntityType(Metadata.DeclaringEntityType.Name) is { } entityType) { entityTypeBuilder = entityType.Builder; } diff --git a/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs b/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs index e7860529d76..0e13bcac7bc 100644 --- a/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.EntityFrameworkCore.Internal; @@ -205,7 +204,7 @@ public static bool IsCompatible(MemberInfo? newMemberInfo, PropertyBase existing if (memberInfo == null || (memberInfo is PropertyInfo propertyInfo && propertyInfo.IsIndexerProperty())) { - if (existingProperty.GetTypeConfigurationSource() is ConfigurationSource existingTypeConfigurationSource + if (existingProperty.GetTypeConfigurationSource() is { } existingTypeConfigurationSource && typeConfigurationSource != null && !typeConfigurationSource.Overrides(existingTypeConfigurationSource)) { @@ -375,8 +374,8 @@ public static bool IsCompatible(MemberInfo? newMemberInfo, PropertyBase existing bool required, bool checkType = false) => CreateUniqueProperties( - new[] { propertyType }, - new[] { propertyName }, + [propertyType], + [propertyName], required, checkTypes: checkType)?.First().Builder; @@ -808,7 +807,7 @@ public virtual bool CanHaveProperty( && (propertyType == null || propertyType == existingProperty.ClrType)) || ((memberInfo == null || (memberInfo is PropertyInfo propertyInfo && propertyInfo.IsIndexerProperty())) - && (existingProperty.GetTypeConfigurationSource() is not ConfigurationSource existingTypeConfigurationSource + && (existingProperty.GetTypeConfigurationSource() is not { } existingTypeConfigurationSource || typeConfigurationSource.Overrides(existingTypeConfigurationSource))) || configurationSource.Overrides(existingProperty.GetConfigurationSource()) : configurationSource.HasValue @@ -1375,7 +1374,10 @@ public virtual bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessM /// doing so can result in application failures when updating to a new Entity Framework Core release. /// protected virtual InternalPropertyBuilder? GetOrCreateDiscriminatorProperty( - Type? type, string? name, MemberInfo? memberInfo, ConfigurationSource configurationSource) + Type? type, + string? name, + MemberInfo? memberInfo, + ConfigurationSource configurationSource) { if (memberInfo != null) { @@ -1401,7 +1403,7 @@ public virtual bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessM type, name, memberInfo, - typeConfigurationSource: type != null ? ConfigurationSource.Convention : null, + typeConfigurationSource: ConfigurationSource.Convention, ConfigurationSource.Convention); if (discriminatorPropertyBuilder == null) @@ -1413,7 +1415,7 @@ public virtual bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessM type, name, memberInfo, - typeConfigurationSource: type != null ? ConfigurationSource.Convention : null, + typeConfigurationSource: ConfigurationSource.Convention, ConfigurationSource.Convention); } @@ -1861,7 +1863,11 @@ bool IConventionTypeBaseBuilder.CanHaveComplexProperty(MemberInfo memberInfo, Ty /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - public IConventionComplexPropertyBuilder? ComplexCollection(Type propertyType, string propertyName, Type? complexType = null, bool fromDataAnnotation = false) + public IConventionComplexPropertyBuilder? ComplexCollection( + Type propertyType, + string propertyName, + Type? complexType = null, + bool fromDataAnnotation = false) => ComplexProperty( propertyType, propertyName, @@ -1878,7 +1884,10 @@ bool IConventionTypeBaseBuilder.CanHaveComplexProperty(MemberInfo memberInfo, Ty /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - public IConventionComplexPropertyBuilder? ComplexCollection(MemberInfo memberInfo, Type? complexType = null, bool fromDataAnnotation = false) + public IConventionComplexPropertyBuilder? ComplexCollection( + MemberInfo memberInfo, + Type? complexType = null, + bool fromDataAnnotation = false) => ComplexProperty( propertyType: memberInfo.GetMemberType(), propertyName: memberInfo.Name, @@ -1888,7 +1897,11 @@ bool IConventionTypeBaseBuilder.CanHaveComplexProperty(MemberInfo memberInfo, Ty collection: true, configurationSource: fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); - bool IConventionTypeBaseBuilder.CanHaveComplexCollection(Type? propertyType, string propertyName, Type? complexType, bool fromDataAnnotation) + bool IConventionTypeBaseBuilder.CanHaveComplexCollection( + Type? propertyType, + string propertyName, + Type? complexType, + bool fromDataAnnotation) => CanHaveComplexProperty( propertyType, propertyName, diff --git a/src/EFCore/Metadata/Internal/Key.cs b/src/EFCore/Metadata/Internal/Key.cs index c8a574d86a3..83626e3f0f3 100644 --- a/src/EFCore/Metadata/Internal/Key.cs +++ b/src/EFCore/Metadata/Internal/Key.cs @@ -18,7 +18,6 @@ public class Key : ConventionAnnotatable, IMutableKey, IConventionKey, IRuntimeK private ConfigurationSource _configurationSource; // Warning: Never access these fields directly as access needs to be thread-safe - private Func? _identityMapFactory; private object? _principalKeyValueFactory; @@ -152,9 +151,10 @@ public virtual IEnumerable GetReferencingForeignKeys() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func IdentityMapFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _identityMapFactory, this, static key => + ref field, this, static key => { key.EnsureReadOnly(); return IdentityMapFactoryFactory.Create(key); diff --git a/src/EFCore/Metadata/Internal/MemberClassifier.cs b/src/EFCore/Metadata/Internal/MemberClassifier.cs index 954b3d77c45..f8cbc64a797 100644 --- a/src/EFCore/Metadata/Internal/MemberClassifier.cs +++ b/src/EFCore/Metadata/Internal/MemberClassifier.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Infrastructure.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -219,7 +218,7 @@ public virtual bool IsCandidateComplexProperty( } var targetType = memberInfo.GetMemberType(); - if (targetType.TryGetElementType(typeof(IList<>)) is Type sequenceType + if (targetType.TryGetElementType(typeof(IList<>)) is { } sequenceType && IsCandidateComplexType(sequenceType.UnwrapNullableType(), model, out explicitlyConfigured)) { elementType = sequenceType; @@ -233,7 +232,7 @@ private static bool IsCandidateComplexType(Type targetType, IConventionModel mod { if (!targetType.IsValidComplexType() || (targetType.IsGenericType - && targetType.GetGenericTypeDefinition() is Type genericTypeDefinition + && targetType.GetGenericTypeDefinition() is var genericTypeDefinition && (genericTypeDefinition == typeof(Dictionary<,>) || genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(HashSet<>) diff --git a/src/EFCore/Metadata/Internal/Model.cs b/src/EFCore/Metadata/Internal/Model.cs index 2dc3aecc280..392e06ee20f 100644 --- a/src/EFCore/Metadata/Internal/Model.cs +++ b/src/EFCore/Metadata/Internal/Model.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal; @@ -427,7 +426,7 @@ public virtual string GetDisplayName(Type type) ? entityType : FindEntityType(entityType.Name) ?? (entityType.HasSharedClrType - ? entityType.FindOwnership() is ForeignKey ownership + ? entityType.FindOwnership() is { } ownership ? FindActualEntityType(ownership.PrincipalEntityType) ?.FindNavigation(ownership.PrincipalToDependent!.Name)?.TargetEntityType : null @@ -478,8 +477,8 @@ public virtual IEnumerable GetEntityTypes(string name) { var entityType = FindEntityType(name); return entityType == null - ? Enumerable.Empty() - : new[] { entityType }; + ? [] + : [entityType]; } /// @@ -643,7 +642,7 @@ public virtual bool IsIgnoredType([DynamicallyAccessedMembers(DynamicallyAccesse /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual IEnumerable GetTypeMappingConfigurations() - => Configuration?.GetTypeMappingConfigurations() ?? Enumerable.Empty(); + => Configuration?.GetTypeMappingConfigurations() ?? []; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1183,7 +1182,7 @@ private Model MakeReadonly() public virtual bool IsIndexerMethod(MethodInfo methodInfo) => !methodInfo.IsStatic && methodInfo is { IsSpecialName: true, DeclaringType: not null } - && FindIndexerPropertyInfo(methodInfo.DeclaringType) is PropertyInfo indexerProperty + && FindIndexerPropertyInfo(methodInfo.DeclaringType) is { } indexerProperty && (methodInfo == indexerProperty.GetMethod || methodInfo == indexerProperty.SetMethod); /// @@ -1601,8 +1600,7 @@ IMutableEntityType IMutableModel.AddEntityType( /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [Obsolete] // The interface didn't mark method obsolete - [DebuggerStepThrough] + [Obsolete, DebuggerStepThrough] // The interface didn't mark method obsolete IConventionEntityType? IConventionModel.AddEntityType( string name, string definingNavigationName, @@ -1631,8 +1629,7 @@ IMutableEntityType IMutableModel.AddEntityType( /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [Obsolete] // The interface didn't mark method obsolete - [DebuggerStepThrough] + [Obsolete, DebuggerStepThrough] // The interface didn't mark method obsolete IConventionEntityType? IConventionModel.AddEntityType( [DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type, string definingNavigationName, diff --git a/src/EFCore/Metadata/Internal/ModelConfiguration.cs b/src/EFCore/Metadata/Internal/ModelConfiguration.cs index 192c97e604a..480b72caf99 100644 --- a/src/EFCore/Metadata/Internal/ModelConfiguration.cs +++ b/src/EFCore/Metadata/Internal/ModelConfiguration.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Dynamic; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; diff --git a/src/EFCore/Metadata/Internal/Navigation.cs b/src/EFCore/Metadata/Internal/Navigation.cs index 46624377320..8166df3a019 100644 --- a/src/EFCore/Metadata/Internal/Navigation.cs +++ b/src/EFCore/Metadata/Internal/Navigation.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -17,7 +16,6 @@ public class Navigation : PropertyBase, IMutableNavigation, IConventionNavigatio private InternalNavigationBuilder? _builder; // Warning: Never access these fields directly as access needs to be thread-safe - private IClrCollectionAccessor? _collectionAccessor; private bool _collectionAccessorInitialized; /// @@ -153,7 +151,8 @@ public virtual bool IsOnDependent /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override bool IsCollection => !IsOnDependent && !ForeignKey.IsUnique; + public override bool IsCollection + => !IsOnDependent && !ForeignKey.IsUnique; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -310,7 +309,7 @@ public virtual Navigation? Inverse /// public virtual IClrCollectionAccessor? CollectionAccessor => NonCapturingLazyInitializer.EnsureInitialized( - ref _collectionAccessor, + ref field, ref _collectionAccessorInitialized, this, static navigation => ClrCollectionAccessorFactory.Instance.Create(navigation)); diff --git a/src/EFCore/Metadata/Internal/Property.cs b/src/EFCore/Metadata/Internal/Property.cs index dd9298618f9..b8209d2eea4 100644 --- a/src/EFCore/Metadata/Internal/Property.cs +++ b/src/EFCore/Metadata/Internal/Property.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -119,15 +118,14 @@ public virtual void SetRemovedFromModel() /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static bool AreCompatible(IReadOnlyList properties, EntityType entityType) - => properties.All( - property => - property.IsShadowProperty() - || (property.IsIndexerProperty() - ? property.PropertyInfo == entityType.FindIndexerPropertyInfo() - : ((property.PropertyInfo != null - && entityType.GetRuntimeProperties().ContainsKey(property.Name)) - || (property.FieldInfo != null - && entityType.GetRuntimeFields().ContainsKey(property.Name))))); + => properties.All(property => + property.IsShadowProperty() + || (property.IsIndexerProperty() + ? property.PropertyInfo == entityType.FindIndexerPropertyInfo() + : ((property.PropertyInfo != null + && entityType.GetRuntimeProperties().ContainsKey(property.Name)) + || (property.FieldInfo != null + && entityType.GetRuntimeFields().ContainsKey(property.Name))))); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -170,7 +168,8 @@ public virtual void UpdateTypeConfigurationSource(ConfigurationSource configurat /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override bool IsCollection => IsPrimitiveCollection; + public override bool IsCollection + => IsPrimitiveCollection; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -895,7 +894,7 @@ public virtual (ValueConverter? ValueConverter, Type? ValueConverterType, Type? new Queue<(Property CurrentProperty, Property CycleBreakingProperty, int CyclePosition, int MaxCycleLength )>(); queue.Enqueue(currentNode.Value); - visitedProperties = new HashSet { property }; + visitedProperties = [property]; } if (visitedProperties?.Contains(principalProperty) == true) @@ -1177,7 +1176,7 @@ public virtual CoreTypeMapping? TypeMapping /// public virtual ValueComparer? GetValueComparer() => IsReadOnly - ? _valueComparer = (GetValueComparer(null) ?? TypeMapping?.Comparer).ToNullableComparer(ClrType) + ? _valueComparer ??= (GetValueComparer(null) ?? TypeMapping?.Comparer).ToNullableComparer(ClrType) : (GetValueComparer(null) ?? TypeMapping?.Comparer).ToNullableComparer(ClrType); private ValueComparer? GetValueComparer(HashSet? checkedProperties) diff --git a/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs b/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs index 5f5fd275929..59c46d11b10 100644 --- a/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs +++ b/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs @@ -259,7 +259,7 @@ private static Expression> CreateRelationshipSna /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static readonly MethodInfo ContainsKeyMethod = - typeof(IDictionary).GetMethod(nameof(IDictionary.ContainsKey), [typeof(string)])!; + typeof(IDictionary).GetMethod(nameof(IDictionary<,>.ContainsKey), [typeof(string)])!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -284,7 +284,8 @@ public static Expression CreateMemberAccess( switch (complexType.ComplexProperty) { case { IsCollection: true } complexProperty when fromEntity: - instanceExpression = CreateComplexCollectionElementAccess(complexProperty, instanceExpression, indicesExpression, fromDeclaringType, fromEntity); + instanceExpression = CreateComplexCollectionElementAccess( + complexProperty, instanceExpression, indicesExpression, fromDeclaringType, fromEntity); break; case { IsCollection: false } complexProperty: instanceExpression = CreateMemberAccess( @@ -316,7 +317,7 @@ public static Expression CreateMemberAccess( { memberAccess = Expression.Condition( Expression.Call( - instanceExpression, ContainsKeyMethod, [Expression.Constant(property.Name)]), + instanceExpression, ContainsKeyMethod, Expression.Constant(property.Name)), memberAccess, memberAccess.Type.GetDefaultValueConstant()); } @@ -328,25 +329,25 @@ public static Expression CreateMemberAccess( return !addNullCheck || instanceExpression.Type.IsValueType - && !instanceExpression.Type.IsNullableValueType() - ? memberAccess - : Expression.Condition( - Expression.Equal(instanceExpression, Expression.Constant(null)), - Expression.Default(memberInfo.GetMemberType()), - memberAccess); + && !instanceExpression.Type.IsNullableValueType() + ? memberAccess + : Expression.Condition( + Expression.Equal(instanceExpression, Expression.Constant(null)), + Expression.Default(memberInfo.GetMemberType()), + memberAccess); } private static readonly MethodInfo ComplexCollectionNotInitializedMethod = typeof(CoreStrings).GetMethod(nameof(CoreStrings.ComplexCollectionNotInitialized), BindingFlags.Static | BindingFlags.Public)!; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public static readonly ConstructorInfo InvalidOperationConstructor = typeof(InvalidOperationException).GetConstructor([typeof(string)])!; + public static readonly ConstructorInfo + InvalidOperationConstructor = typeof(InvalidOperationException).GetConstructor([typeof(string)])!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Internal/PropertyBase.cs b/src/EFCore/Metadata/Internal/PropertyBase.cs index 5e9a24205f6..b277ecab38a 100644 --- a/src/EFCore/Metadata/Internal/PropertyBase.cs +++ b/src/EFCore/Metadata/Internal/PropertyBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -20,12 +19,8 @@ public abstract class PropertyBase : ConventionAnnotatable, IMutablePropertyBase private ConfigurationSource? _fieldInfoConfigurationSource; // Warning: Never access these fields directly as access needs to be thread-safe - private IClrPropertyGetter? _getter; private IClrPropertySetter? _setter; - private IClrPropertySetter? _materializationSetter; private IClrIndexedCollectionAccessor? _clrIndexedCollectionAccessor; - private PropertyAccessors? _accessors; - private PropertyIndexes? _indexes; private IComparer? _currentValueComparer; /// @@ -340,17 +335,18 @@ public static bool IsCompatible( /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual PropertyIndexes PropertyIndexes { get => NonCapturingLazyInitializer.EnsureInitialized( - ref _indexes, this, + ref field, this, static property => { property.EnsureReadOnly(); ((IRuntimeEntityType)(((IRuntimeTypeBase)property.DeclaringType).ContainingEntityType)).CalculateCounts(); }); - set => NonCapturingLazyInitializer.EnsureInitialized(ref _indexes, value); + set => NonCapturingLazyInitializer.EnsureInitialized(ref field, value); } /// @@ -359,9 +355,10 @@ public virtual PropertyIndexes PropertyIndexes /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual IClrPropertyGetter Getter => NonCapturingLazyInitializer.EnsureInitialized( - ref _getter, this, static property => + ref field, this, static property => { property.EnsureReadOnly(); return ClrPropertyGetterFactory.Instance.Create(property); @@ -387,9 +384,10 @@ public virtual IClrPropertySetter GetSetter() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual IClrPropertySetter MaterializationSetter => NonCapturingLazyInitializer.EnsureInitialized( - ref _materializationSetter, this, static property => + ref field, this, static property => { property.EnsureReadOnly(); return ClrPropertyMaterializationSetterFactory.Instance.Create(property); @@ -418,9 +416,10 @@ public IClrIndexedCollectionAccessor GetIndexedCollectionAccessor() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual PropertyAccessors Accessors => NonCapturingLazyInitializer.EnsureInitialized( - ref _accessors, this, static property => + ref field, this, static property => { property.EnsureReadOnly(); return PropertyAccessorsFactory.Instance.Create(property); diff --git a/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs b/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs index 9db87924859..19b27dace99 100644 --- a/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs +++ b/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs @@ -342,10 +342,11 @@ private static string GetNoFieldErrorMessage(IPropertyBase propertyBase) => propertyBase.DeclaringType switch { EntityType entityType - when entityType.GetServiceProperties().Any(p => typeof(ILazyLoader).IsAssignableFrom(p.ClrType)) + when entityType.GetServiceProperties().Any(p => typeof(ILazyLoader).IsAssignableFrom(p.ClrType)) || entityType.ConstructorBinding?.ParameterBindings .OfType() - .Any(b => b.ServiceType == typeof(ILazyLoader)) == true + .Any(b => b.ServiceType == typeof(ILazyLoader)) + == true => CoreStrings.NoBackingFieldLazyLoading( propertyBase.Name, propertyBase.DeclaringType.DisplayName()), _ => CoreStrings.NoBackingField( diff --git a/src/EFCore/Metadata/Internal/QueryFilter.cs b/src/EFCore/Metadata/Internal/QueryFilter.cs index b7b47d936f8..460e7065daf 100644 --- a/src/EFCore/Metadata/Internal/QueryFilter.cs +++ b/src/EFCore/Metadata/Internal/QueryFilter.cs @@ -4,7 +4,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal; /// -/// Represents a query filter in a model. +/// Represents a query filter in a model. /// /// The key of the query filter. /// The expression representing the filter. @@ -41,7 +41,8 @@ public class QueryFilter(string? key, LambdaExpression? expression) : IQueryFilt /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(LambdaExpression? expression, ConfigurationSource configurationSource) - : this(null, expression) => ConfigurationSource = configurationSource; + : this(null, expression) + => ConfigurationSource = configurationSource; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -50,7 +51,8 @@ public QueryFilter(LambdaExpression? expression, ConfigurationSource configurati /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(string key, LambdaExpression? expression, ConfigurationSource configurationSource) - : this(key, expression) => ConfigurationSource = configurationSource; + : this(key, expression) + => ConfigurationSource = configurationSource; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -58,7 +60,8 @@ public QueryFilter(string key, LambdaExpression? expression, ConfigurationSource /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public QueryFilter(LambdaExpression? expression) : this(null, expression) + public QueryFilter(LambdaExpression? expression) + : this(null, expression) { } @@ -69,7 +72,8 @@ public QueryFilter(LambdaExpression? expression) : this(null, expression) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(string key, LambdaExpression? expression, bool fromDataAnnotation) - : this(key, expression) => ConfigurationSource = fromDataAnnotation + : this(key, expression) + => ConfigurationSource = fromDataAnnotation ? Metadata.ConfigurationSource.DataAnnotation : Metadata.ConfigurationSource.Convention; @@ -80,7 +84,8 @@ public QueryFilter(string key, LambdaExpression? expression, bool fromDataAnnota /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(LambdaExpression? expression, bool fromDataAnnotation) - : this(expression) => ConfigurationSource = fromDataAnnotation + : this(expression) + => ConfigurationSource = fromDataAnnotation ? Metadata.ConfigurationSource.DataAnnotation : Metadata.ConfigurationSource.Convention; } diff --git a/src/EFCore/Metadata/Internal/QueryFilterCollection.cs b/src/EFCore/Metadata/Internal/QueryFilterCollection.cs index dce90705950..7c77c66765e 100644 --- a/src/EFCore/Metadata/Internal/QueryFilterCollection.cs +++ b/src/EFCore/Metadata/Internal/QueryFilterCollection.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -14,8 +13,8 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal; /// public sealed class QueryFilterCollection : IReadOnlyCollection { - private IQueryFilter? anonymousFilter; - private Dictionary? filters; + private IQueryFilter? _anonymousFilter; + private Dictionary? _filters; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -33,10 +32,12 @@ public QueryFilterCollection() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public QueryFilterCollection(IEnumerable filters) => SetRange(filters); + public QueryFilterCollection(IEnumerable filters) + => SetRange(filters); - [MemberNotNullWhen(true, nameof(anonymousFilter))] - private bool HasAnonymousFilter => anonymousFilter != null; + [MemberNotNullWhen(true, nameof(_anonymousFilter))] + private bool HasAnonymousFilter + => _anonymousFilter != null; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -44,9 +45,10 @@ public QueryFilterCollection() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public int Count => HasAnonymousFilter - ? 1 - : filters?.Count + public int Count + => HasAnonymousFilter + ? 1 + : _filters?.Count ?? 0; /// @@ -55,11 +57,14 @@ public QueryFilterCollection() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public IEnumerator GetEnumerator() => HasAnonymousFilter - ? new AnonymousFilterEnumerator(anonymousFilter) - : filters?.Values.GetEnumerator() + public IEnumerator GetEnumerator() + => HasAnonymousFilter + ? new AnonymousFilterEnumerator(_anonymousFilter) + : _filters?.Values.GetEnumerator() ?? Enumerable.Empty().GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -68,16 +73,7 @@ public IEnumerator GetEnumerator() => HasAnonymousFilter /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public IQueryFilter? this[string? filterKey] - { - get - { - if(filterKey == null) - { - return anonymousFilter; - } - return filters?.GetValueOrDefault(filterKey); - } - } + => filterKey == null ? _anonymousFilter : _filters?.GetValueOrDefault(filterKey); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -86,7 +82,7 @@ public IQueryFilter? this[string? filterKey] /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public IQueryFilter? Set(IQueryFilter? filter) - { + { if (filter == null) { Remove(); @@ -97,11 +93,12 @@ public IQueryFilter? this[string? filterKey] } else if (filter.IsAnonymous) { - if(filters?.Count > 0) + if (_filters?.Count > 0) { throw new InvalidOperationException(CoreStrings.AnonymousAndNamedFiltersCombined); } - anonymousFilter = filter; + + _anonymousFilter = filter; } else { @@ -109,7 +106,8 @@ public IQueryFilter? this[string? filterKey] { throw new InvalidOperationException(CoreStrings.AnonymousAndNamedFiltersCombined); } - (filters ??= [])[filter.Key] = filter; + + (_filters ??= [])[filter.Key] = filter; } return filter; @@ -123,9 +121,9 @@ public IQueryFilter? this[string? filterKey] /// public void SetRange(IEnumerable newFilters) { - if(filters == null && newFilters.TryGetNonEnumeratedCount(out var count) && count > 1) + if (_filters == null && newFilters.TryGetNonEnumeratedCount(out var count) && count > 1) { - filters = new(count); + _filters = new Dictionary(count); } foreach (var filter in newFilters) @@ -136,35 +134,35 @@ public void SetRange(IEnumerable newFilters) private void Remove(string? key = null) { - if(key == null) + if (key == null) { - anonymousFilter = null; + _anonymousFilter = null; } else { - filters?.Remove(key); + _filters?.Remove(key); } } - sealed class AnonymousFilterEnumerator(IQueryFilter filter) : IEnumerator + private sealed class AnonymousFilterEnumerator(IQueryFilter filter) : IEnumerator { - private readonly IQueryFilter _filter = filter; + private int _position = -1; - int position = -1; + public IQueryFilter Current + => _position == 0 ? filter : null!; - public IQueryFilter Current => position == 0 ? _filter : null!; - - object IEnumerator.Current => Current; + object IEnumerator.Current + => Current; public void Dispose() { } + public bool MoveNext() { - position++; - return position < 1; + _position++; + return _position < 1; } + public void Reset() - { - position = -1; - } + => _position = -1; } } diff --git a/src/EFCore/Metadata/Internal/ServiceProperty.cs b/src/EFCore/Metadata/Internal/ServiceProperty.cs index f2c1b0423a5..b25e3fcc1a3 100644 --- a/src/EFCore/Metadata/Internal/ServiceProperty.cs +++ b/src/EFCore/Metadata/Internal/ServiceProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -97,7 +96,8 @@ public virtual bool IsInModel /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override bool IsCollection => false; + public override bool IsCollection + => false; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Internal/SkipNavigation.cs b/src/EFCore/Metadata/Internal/SkipNavigation.cs index 68376547ffa..b9d52206c7f 100644 --- a/src/EFCore/Metadata/Internal/SkipNavigation.cs +++ b/src/EFCore/Metadata/Internal/SkipNavigation.cs @@ -19,9 +19,7 @@ public class SkipNavigation : PropertyBase, IMutableSkipNavigation, IConventionS private readonly Type _type; // Warning: Never access these fields directly as access needs to be thread-safe - private IClrCollectionAccessor? _collectionAccessor; private bool _collectionAccessorInitialized; - private ICollectionLoader? _manyToManyLoader; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -354,7 +352,7 @@ public virtual object? Sentinel /// public virtual IClrCollectionAccessor? CollectionAccessor => NonCapturingLazyInitializer.EnsureInitialized( - ref _collectionAccessor, + ref field, ref _collectionAccessorInitialized, this, static navigation => @@ -369,9 +367,10 @@ public virtual IClrCollectionAccessor? CollectionAccessor /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual ICollectionLoader ManyToManyLoader => NonCapturingLazyInitializer.EnsureInitialized( - ref _manyToManyLoader, this, static navigation => + ref field, this, static navigation => { navigation.EnsureReadOnly(); return ManyToManyLoaderFactory.Instance.Create(navigation); diff --git a/src/EFCore/Metadata/Internal/TypeBase.cs b/src/EFCore/Metadata/Internal/TypeBase.cs index cdc8dc6602c..208cce8a68e 100644 --- a/src/EFCore/Metadata/Internal/TypeBase.cs +++ b/src/EFCore/Metadata/Internal/TypeBase.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -35,12 +34,6 @@ public abstract class TypeBase : ConventionAnnotatable, IMutableTypeBase, IConve private SortedDictionary? _runtimeProperties; private SortedDictionary? _runtimeFields; - private Func? _originalValuesFactory; - private Func? _storeGeneratedValuesFactory; - private Func? _temporaryValuesFactory; - private Func, ISnapshot>? _shadowValuesFactory; - private Func? _emptyShadowValuesFactory; - // _serviceOnlyConstructorBinding needs to be set as well whenever _constructorBinding is set private InstantiationBinding? _constructorBinding; private InstantiationBinding? _serviceOnlyConstructorBinding; @@ -319,12 +312,14 @@ public virtual void UpdateConfigurationSource(ConfigurationSource configurationS /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func OriginalValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _originalValuesFactory, this, + ref field, this, static structuralType => { - Check.DebugAssert(structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, + Check.DebugAssert( + structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, $"ComplexType {structuralType.Name} is not a collection"); structuralType.EnsureReadOnly(); @@ -337,12 +332,14 @@ public virtual Func OriginalValuesFactory /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func StoreGeneratedValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _storeGeneratedValuesFactory, this, + ref field, this, static structuralType => { - Check.DebugAssert(structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, + Check.DebugAssert( + structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, $"ComplexType {structuralType.Name} is not a collection"); structuralType.EnsureReadOnly(); @@ -355,12 +352,14 @@ public virtual Func StoreGeneratedValuesFactory /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func TemporaryValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _temporaryValuesFactory, this, + ref field, this, static structuralType => { - Check.DebugAssert(structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, + Check.DebugAssert( + structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, $"ComplexType {structuralType.Name} is not a collection"); structuralType.EnsureReadOnly(); @@ -373,12 +372,14 @@ public virtual Func TemporaryValuesFactory /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func, ISnapshot> ShadowValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _shadowValuesFactory, this, + ref field, this, static structuralType => { - Check.DebugAssert(structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, + Check.DebugAssert( + structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, $"ComplexType {structuralType.Name} is not a collection"); structuralType.EnsureReadOnly(); @@ -391,12 +392,14 @@ public virtual Func TemporaryValuesFactory /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [field: AllowNull, MaybeNull] public virtual Func EmptyShadowValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( - ref _emptyShadowValuesFactory, this, + ref field, this, static structuralType => { - Check.DebugAssert(structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, + Check.DebugAssert( + structuralType is not ComplexType complexType || complexType.ComplexProperty.IsCollection, $"ComplexType {structuralType.Name} is not a collection"); structuralType.EnsureReadOnly(); @@ -722,7 +725,7 @@ public virtual IEnumerable GetDeclaredProperties() /// public virtual IEnumerable GetDerivedProperties() => _directlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredProperties()); /// @@ -736,7 +739,7 @@ public virtual IEnumerable FindDerivedProperties(string propertyName) Check.NotNull(propertyName); return _directlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes().Select(et => et.FindDeclaredProperty(propertyName)).Where(p => p != null); } @@ -1148,7 +1151,7 @@ public virtual IEnumerable GetDeclaredComplexProperties() /// public virtual IEnumerable GetDerivedComplexProperties() => _directlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredComplexProperties()); /// @@ -1162,7 +1165,7 @@ public virtual IEnumerable FindDerivedComplexProperties(string Check.NotNull(propertyName); return _directlyDerivedTypes.Count == 0 - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredComplexProperty(propertyName)).Where(p => p != null); } @@ -1226,8 +1229,6 @@ public virtual IEnumerable FindComplexPropertiesInHierarchy(str property.DeclaringType.DisplayName())); } - CheckPropertyNotInUse(property); - property.SetRemovedFromModel(); var removed = _complexProperties.Remove(property.Name); @@ -1236,10 +1237,6 @@ public virtual IEnumerable FindComplexPropertiesInHierarchy(str return (ComplexProperty?)Model.ConventionDispatcher.OnComplexPropertyRemoved(BaseBuilder, property); } - private void CheckPropertyNotInUse(ComplexProperty property) - { - } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -1458,6 +1455,7 @@ public virtual bool IsIgnored(string name) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + // ReSharper disable once MemberHidesInterfaceMemberWithDefaultImplementation private string DisplayName() => ((IReadOnlyTypeBase)this).DisplayName(); @@ -1496,7 +1494,6 @@ public virtual InstantiationBinding? ConstructorBinding set => SetConstructorBinding(value, ConfigurationSource.Explicit); } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -2487,7 +2484,7 @@ IEnumerable IReadOnlyTypeBase.GetDerivedComplexPropert /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - IMutableComplexProperty? IMutableTypeBase.RemoveComplexProperty(IReadOnlyProperty property) + IMutableComplexProperty? IMutableTypeBase.RemoveComplexProperty(IReadOnlyComplexProperty property) => RemoveComplexProperty((ComplexProperty)property); /// diff --git a/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs b/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs index 80abde1b829..31148813ea8 100644 --- a/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs +++ b/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs @@ -27,7 +27,7 @@ public static bool UseEagerSnapshots(this IReadOnlyTypeBase complexType) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static string ShortNameChain(this IReadOnlyTypeBase structuralType) - => (structuralType is IReadOnlyComplexType complexType) && (complexType.ComplexProperty is IReadOnlyComplexProperty complexProperty) + => (structuralType is IReadOnlyComplexType { ComplexProperty: var complexProperty }) ? complexProperty.DeclaringType.ShortNameChain() + (complexProperty.IsCollection ? "[]" : ".") + structuralType.ShortName() : structuralType.ShortName(); @@ -45,10 +45,10 @@ public static T CheckContains(this IReadOnlyTypeBase structuralType, T proper return !property.DeclaringType.IsAssignableFrom(structuralType) && (!((IRuntimeTypeBase)property.DeclaringType).ContainingEntryType.IsAssignableFrom(structuralType) || (property.DeclaringType is IComplexType complexType - && complexType.ComplexProperty.IsCollection)) + && complexType.ComplexProperty.IsCollection)) && structuralType.ClrType != typeof(object) // For testing - ? throw new InvalidOperationException( - CoreStrings.PropertyDoesNotBelong(property.Name, property.DeclaringType.DisplayName(), structuralType.DisplayName())) - : property; + ? throw new InvalidOperationException( + CoreStrings.PropertyDoesNotBelong(property.Name, property.DeclaringType.DisplayName(), structuralType.DisplayName())) + : property; } } diff --git a/src/EFCore/Metadata/Internal/TypeIdentity.cs b/src/EFCore/Metadata/Internal/TypeIdentity.cs index 8afe68643d0..34a89b7913e 100644 --- a/src/EFCore/Metadata/Internal/TypeIdentity.cs +++ b/src/EFCore/Metadata/Internal/TypeIdentity.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Metadata.Internal; /// diff --git a/src/EFCore/Metadata/LazyLoaderParameterBindingFactory.cs b/src/EFCore/Metadata/LazyLoaderParameterBindingFactory.cs index c2ffb1df028..bda704d7368 100644 --- a/src/EFCore/Metadata/LazyLoaderParameterBindingFactory.cs +++ b/src/EFCore/Metadata/LazyLoaderParameterBindingFactory.cs @@ -37,7 +37,7 @@ public LazyLoaderParameterBindingFactory(LazyLoaderParameterBindingFactoryDepend protected virtual LazyLoaderParameterBindingFactoryDependencies Dependencies { get; } /// - /// Checks whether or not this factory can bind a parameter with the given type and name. + /// Checks whether this factory can bind a parameter with the given type and name. /// /// The parameter type. /// The parameter name. diff --git a/src/EFCore/Metadata/ObjectArrayParameterBinding.cs b/src/EFCore/Metadata/ObjectArrayParameterBinding.cs index 28d780c455d..092118e9299 100644 --- a/src/EFCore/Metadata/ObjectArrayParameterBinding.cs +++ b/src/EFCore/Metadata/ObjectArrayParameterBinding.cs @@ -35,18 +35,17 @@ public ObjectArrayParameterBinding(IReadOnlyList bindings) public override Expression BindToParameter(ParameterBindingInfo bindingInfo) => Expression.NewArrayInit( typeof(object), - _bindings.Select( - b => - { - var expression = b.BindToParameter(bindingInfo); + _bindings.Select(b => + { + var expression = b.BindToParameter(bindingInfo); - if (expression.Type.IsValueType) - { - expression = Expression.Convert(expression, typeof(object)); - } + if (expression.Type.IsValueType) + { + expression = Expression.Convert(expression, typeof(object)); + } - return expression; - })); + return expression; + })); /// /// Creates a copy that contains the given consumed properties. diff --git a/src/EFCore/Metadata/RuntimeComplexProperty.cs b/src/EFCore/Metadata/RuntimeComplexProperty.cs index bd1e828f530..cbe58edb356 100644 --- a/src/EFCore/Metadata/RuntimeComplexProperty.cs +++ b/src/EFCore/Metadata/RuntimeComplexProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; diff --git a/src/EFCore/Metadata/RuntimeComplexType.cs b/src/EFCore/Metadata/RuntimeComplexType.cs index dd71a31f3fc..eebbf906467 100644 --- a/src/EFCore/Metadata/RuntimeComplexType.cs +++ b/src/EFCore/Metadata/RuntimeComplexType.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -56,7 +55,8 @@ public RuntimeComplexType( }; ContainingEntryType = ComplexProperty.DeclaringType switch { - RuntimeComplexType declaringComplexType when !declaringComplexType.ComplexProperty.IsCollection => declaringComplexType.ContainingEntryType, + RuntimeComplexType declaringComplexType when !declaringComplexType.ComplexProperty.IsCollection => declaringComplexType + .ContainingEntryType, _ => ComplexProperty.DeclaringType }; } @@ -167,6 +167,7 @@ public override PropertyCounts CalculateCounts() // This will calculate the _counts for all contained complex collections var _ = ContainingEntityType.CalculateCounts(); } + return _counts!; } @@ -176,7 +177,8 @@ public override PropertyCounts CalculateCounts() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual void SetCounts(PropertyCounts value) => _counts = value; + public virtual void SetCounts(PropertyCounts value) + => _counts = value; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/RuntimeEntityType.cs b/src/EFCore/Metadata/RuntimeEntityType.cs index a605372373c..0b266b8ca82 100644 --- a/src/EFCore/Metadata/RuntimeEntityType.cs +++ b/src/EFCore/Metadata/RuntimeEntityType.cs @@ -1,11 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using EntityTypeExtensions = Microsoft.EntityFrameworkCore.Metadata.Internal.EntityTypeExtensions; namespace Microsoft.EntityFrameworkCore.Metadata; @@ -84,11 +84,13 @@ public RuntimeEntityType( if (servicePropertyCount > 0) { - _serviceProperties = new Utilities.OrderedDictionary(servicePropertyCount, StringComparer.Ordinal); + _serviceProperties = + new Utilities.OrderedDictionary(servicePropertyCount, StringComparer.Ordinal); } _unnamedIndexes = - new Utilities.OrderedDictionary, RuntimeIndex>(unnamedIndexCount, PropertyListComparer.Instance); + new Utilities.OrderedDictionary, RuntimeIndex>( + unnamedIndexCount, PropertyListComparer.Instance); if (namedIndexCount > 0) { _namedIndexes = new Utilities.OrderedDictionary(namedIndexCount, StringComparer.Ordinal); @@ -291,7 +293,7 @@ public virtual List GetDeclaredForeignKeys() private IEnumerable GetDerivedForeignKeys() => !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : GetDerivedTypes().Cast().SelectMany(et => et._foreignKeys); /// @@ -312,7 +314,7 @@ public virtual IEnumerable GetForeignKeys() /// Declared foreign keys. public virtual IEnumerable FindDeclaredForeignKeys(IReadOnlyList properties) => _foreignKeys.Count == 0 - ? Enumerable.Empty() + ? [] : _foreignKeys.Where(fk => PropertyListComparer.Instance.Equals(fk.Properties, properties)); private RuntimeForeignKey? FindDeclaredForeignKey( @@ -409,7 +411,7 @@ private IEnumerable FindDerivedNavigations(string name) Check.NotNull(name); return !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredNavigation(name)).Where(n => n != null); } @@ -494,7 +496,7 @@ private IEnumerable GetDeclaredSkipNavigations() private IEnumerable GetDerivedSkipNavigations() => !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : GetDerivedTypes().Cast().SelectMany(et => et.GetDeclaredSkipNavigations()); private IEnumerable GetSkipNavigations() @@ -509,7 +511,7 @@ private IEnumerable FindDerivedSkipNavigations(string nam Check.NotNull(name); return !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredSkipNavigation(name)).Where(n => n != null); } @@ -599,7 +601,7 @@ public virtual IEnumerable GetDeclaredIndexes() private IEnumerable GetDerivedIndexes() => !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : GetDerivedTypes().Cast().SelectMany(et => et.GetDeclaredIndexes()); /// @@ -637,7 +639,8 @@ public virtual RuntimeServiceProperty AddServiceProperty( this, propertyAccessMode); - (_serviceProperties ??= new Utilities.OrderedDictionary(StringComparer.Ordinal))[serviceProperty.Name] = + (_serviceProperties ??= new Utilities.OrderedDictionary(StringComparer.Ordinal))[ + serviceProperty.Name] = serviceProperty; return serviceProperty; @@ -675,7 +678,7 @@ private IEnumerable GetDeclaredServiceProperties() private IEnumerable GetDerivedServiceProperties() => !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : GetDerivedTypes().Cast().SelectMany(et => et.GetDeclaredServiceProperties()); /// @@ -689,7 +692,7 @@ private IEnumerable FindDerivedServiceProperties(string Check.NotNull(propertyName); return !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredServiceProperty(propertyName)) .Where(p => p != null); @@ -846,10 +849,10 @@ public virtual InstantiationBinding? ServiceOnlyConstructorBinding /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - public override PropertyCounts CalculateCounts() => - NonCapturingLazyInitializer.EnsureInitialized( + public override PropertyCounts CalculateCounts() + => NonCapturingLazyInitializer.EnsureInitialized( ref _counts, this, static entityType => - Internal.EntityTypeExtensions.CalculateCounts(entityType)); + EntityTypeExtensions.CalculateCounts(entityType)); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -857,7 +860,8 @@ public override PropertyCounts CalculateCounts() => /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual void SetCounts(PropertyCounts counts) => _counts = counts; + public virtual void SetCounts(PropertyCounts counts) + => _counts = counts; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -917,8 +921,7 @@ IReadOnlyCollection IReadOnlyEntityType.GetDeclaredQueryFilters() => (IReadOnlyCollection?)this[CoreAnnotationNames.QueryFilter] ?? []; /// - [DebuggerStepThrough] - [Obsolete("Use GetDeclaredQueryFilters() instead.")] + [DebuggerStepThrough, Obsolete("Use GetDeclaredQueryFilters() instead.")] LambdaExpression? IReadOnlyEntityType.GetQueryFilter() => ((IReadOnlyEntityType)this).GetDeclaredQueryFilters().FirstOrDefault(f => f.IsAnonymous)?.Expression; @@ -1133,7 +1136,7 @@ IEnumerable IEntityType.GetDeclaredNavigations() [DebuggerStepThrough] IEnumerable IReadOnlyEntityType.GetDerivedNavigations() => !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : GetDerivedTypes().Cast().SelectMany(et => et.GetDeclaredNavigations()); /// @@ -1271,6 +1274,16 @@ IEnumerable IReadOnlyEntityType.GetDeclaredTriggers() IEnumerable IEntityType.GetDeclaredTriggers() => GetDeclaredTriggers(); + /// + [DebuggerStepThrough] + IEnumerable IReadOnlyEntityType.GetTriggers() + => GetTriggers(); + + /// + [DebuggerStepThrough] + IEnumerable IEntityType.GetTriggers() + => GetTriggers(); + /// [DebuggerStepThrough] IProperty? IEntityType.FindProperty(string name) diff --git a/src/EFCore/Metadata/RuntimeForeignKey.cs b/src/EFCore/Metadata/RuntimeForeignKey.cs index 3b39df7fb54..b3cd6e91cdb 100644 --- a/src/EFCore/Metadata/RuntimeForeignKey.cs +++ b/src/EFCore/Metadata/RuntimeForeignKey.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -22,8 +21,8 @@ public class RuntimeForeignKey : RuntimeAnnotatableBase, IRuntimeForeignKey private readonly bool _isRequiredDependent; private readonly bool _isOwnership; + // Note: This is set and used only by KeyValueFactoryFactory, which ensures thread-safety private IDependentKeyValueFactory? _dependentKeyValueFactory; - private Func? _dependentsMapFactory; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -267,7 +266,6 @@ IDependentKeyValueFactory IForeignKey.GetDependentKeyValueFactory() IDependentKeyValueFactory IForeignKey.GetDependentKeyValueFactory() => _dependentKeyValueFactory!; - // Note: This is set and used only by KeyValueFactoryFactory, which ensures thread-safety /// IDependentKeyValueFactory IRuntimeForeignKey.DependentKeyValueFactory { @@ -278,14 +276,7 @@ IDependentKeyValueFactory IRuntimeForeignKey.DependentKeyValueFactory set => _dependentKeyValueFactory = value; } - // Note: This is set and used only by KeyValueFactoryFactory, which ensures thread-safety /// - Func IRuntimeForeignKey.DependentsMapFactory - { - [DebuggerStepThrough] - get => _dependentsMapFactory!; - - [DebuggerStepThrough] - set => _dependentsMapFactory = value; - } + [field: AllowNull, MaybeNull] + Func IRuntimeForeignKey.DependentsMapFactory { get; set; } = null!; } diff --git a/src/EFCore/Metadata/RuntimeModel.cs b/src/EFCore/Metadata/RuntimeModel.cs index bab0de72d9f..9ef24ca8640 100644 --- a/src/EFCore/Metadata/RuntimeModel.cs +++ b/src/EFCore/Metadata/RuntimeModel.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -47,8 +46,7 @@ public class RuntimeModel : RuntimeAnnotatableBase, IRuntimeModel /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [EntityFrameworkInternal] - [Obsolete("Use a constructor with parameters")] + [EntityFrameworkInternal, Obsolete("Use a constructor with parameters")] public RuntimeModel() { _entityTypes = new Dictionary(StringComparer.Ordinal); @@ -87,8 +85,7 @@ public virtual void SetSkipDetectChanges(bool skipDetectChanges) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [EntityFrameworkInternal] - [Obsolete("This is set in the constructor now")] + [EntityFrameworkInternal, Obsolete("This is set in the constructor now")] public virtual Guid ModelId { get => _modelId; set => _modelId = value; } /// @@ -258,7 +255,7 @@ private IEnumerable GetEntityTypes() /// /// The type of value the property will hold. /// The maximum length of data that is allowed in this property type. - /// A value indicating whether or not the property can persist Unicode characters. + /// A value indicating whether the property can persist Unicode characters. /// The precision of data that is allowed in this property type. /// The scale of data that is allowed in this property type. /// @@ -353,7 +350,7 @@ ChangeTrackingStrategy IReadOnlyModel.GetChangeTrackingStrategy() bool IModel.IsIndexerMethod(MethodInfo methodInfo) => !methodInfo.IsStatic && methodInfo is { IsSpecialName: true, DeclaringType: not null } - && FindIndexerPropertyInfo(methodInfo.DeclaringType) is PropertyInfo indexerProperty + && FindIndexerPropertyInfo(methodInfo.DeclaringType) is { } indexerProperty && (methodInfo == indexerProperty.GetMethod || methodInfo == indexerProperty.SetMethod); /// diff --git a/src/EFCore/Metadata/RuntimeNavigation.cs b/src/EFCore/Metadata/RuntimeNavigation.cs index a96ca571849..31b02d1f4ff 100644 --- a/src/EFCore/Metadata/RuntimeNavigation.cs +++ b/src/EFCore/Metadata/RuntimeNavigation.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -81,7 +80,8 @@ public override RuntimeTypeBase DeclaringType /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override bool IsCollection => !((IReadOnlyNavigation)this).IsOnDependent && !((IReadOnlyForeignKey)ForeignKey).IsUnique; + public override bool IsCollection + => !((IReadOnlyNavigation)this).IsOnDependent && !((IReadOnlyForeignKey)ForeignKey).IsUnique; /// public override object? Sentinel diff --git a/src/EFCore/Metadata/RuntimeProperty.cs b/src/EFCore/Metadata/RuntimeProperty.cs index a9e0eabd1d2..54b65638029 100644 --- a/src/EFCore/Metadata/RuntimeProperty.cs +++ b/src/EFCore/Metadata/RuntimeProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -125,7 +124,7 @@ public virtual void SetSentinelFromProviderValue(object? providerValue) /// The type of value the property will hold. /// A value indicating whether this property can contain . /// The maximum length of data that is allowed in this property. - /// A value indicating whether or not the property can persist Unicode characters. + /// A value indicating whether the property can persist Unicode characters. /// The precision of data that is allowed in this property. /// The scale of data that is allowed in this property. /// @@ -180,7 +179,8 @@ public virtual RuntimeElementType SetElementType( public override RuntimeTypeBase DeclaringType { get; } /// - public override bool IsCollection => IsPrimitiveCollection; + public override bool IsCollection + => IsPrimitiveCollection; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/RuntimePropertyBase.cs b/src/EFCore/Metadata/RuntimePropertyBase.cs index 89814cf2572..3cfc93221cd 100644 --- a/src/EFCore/Metadata/RuntimePropertyBase.cs +++ b/src/EFCore/Metadata/RuntimePropertyBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -132,7 +131,8 @@ public virtual void SetAccessors( /// [EntityFrameworkInternal] public virtual void SetMaterializationSetter( - Action, TValue> setClrValueUsingContainingEntity, Func setClrValue) + Action, TValue> setClrValueUsingContainingEntity, + Func setClrValue) where TEntity : class => _materializationSetter = new ClrPropertySetter(setClrValueUsingContainingEntity, setClrValue); @@ -183,7 +183,8 @@ public virtual void SetIndexedCollectionAccessor /// [EntityFrameworkInternal] public virtual void SetSetter( - Action, TValue> setClrValueUsingContainingEntity, Func setClrValue) + Action, TValue> setClrValueUsingContainingEntity, + Func setClrValue) where TEntity : class => _setter = new ClrPropertySetter(setClrValueUsingContainingEntity, setClrValue); @@ -298,9 +299,9 @@ IClrIndexedCollectionAccessor IRuntimePropertyBase.GetIndexedCollectionAccessor( => IsCollection ? NonCapturingLazyInitializer.EnsureInitialized( ref _clrIndexedCollectionAccessor, this, static property => - RuntimeFeature.IsDynamicCodeSupported - ? ClrIndexedCollectionAccessorFactory.Instance.Create(property)! - : throw new InvalidOperationException(CoreStrings.NativeAotNoCompiledModel)) + RuntimeFeature.IsDynamicCodeSupported + ? ClrIndexedCollectionAccessorFactory.Instance.Create(property)! + : throw new InvalidOperationException(CoreStrings.NativeAotNoCompiledModel)) : throw new InvalidOperationException( CoreStrings.PropertyIsNotACollection(DeclaringType.Name, Name)); diff --git a/src/EFCore/Metadata/RuntimeServiceProperty.cs b/src/EFCore/Metadata/RuntimeServiceProperty.cs index f7e06de0901..fce985d835d 100644 --- a/src/EFCore/Metadata/RuntimeServiceProperty.cs +++ b/src/EFCore/Metadata/RuntimeServiceProperty.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -16,8 +15,6 @@ namespace Microsoft.EntityFrameworkCore.Metadata; /// public class RuntimeServiceProperty : RuntimePropertyBase, IRuntimeServiceProperty { - private ServiceParameterBinding? _parameterBinding; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -61,15 +58,17 @@ public override RuntimeTypeBase DeclaringType /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override bool IsCollection => false; + public override bool IsCollection + => false; /// /// The for this property. /// + [field: AllowNull, MaybeNull] public virtual ServiceParameterBinding ParameterBinding { get => NonCapturingLazyInitializer.EnsureInitialized( - ref _parameterBinding, (IServiceProperty)this, static property => + ref field, (IServiceProperty)this, static property => { var entityType = property.DeclaringEntityType; var factory = entityType.Model.GetModelDependencies().ParameterBindingFactories @@ -78,7 +77,7 @@ public virtual ServiceParameterBinding ParameterBinding }); [DebuggerStepThrough] - set => _parameterBinding = value; + set; } /// diff --git a/src/EFCore/Metadata/RuntimeSkipNavigation.cs b/src/EFCore/Metadata/RuntimeSkipNavigation.cs index 5419c87282e..623d223101e 100644 --- a/src/EFCore/Metadata/RuntimeSkipNavigation.cs +++ b/src/EFCore/Metadata/RuntimeSkipNavigation.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -103,7 +102,8 @@ public override RuntimeTypeBase DeclaringType /// /// Gets a value indicating whether the property is a collection. /// - public override bool IsCollection => _isCollection; + public override bool IsCollection + => _isCollection; /// public override object? Sentinel diff --git a/src/EFCore/Metadata/RuntimeTypeBase.cs b/src/EFCore/Metadata/RuntimeTypeBase.cs index 04e754e9d89..bab0bed258d 100644 --- a/src/EFCore/Metadata/RuntimeTypeBase.cs +++ b/src/EFCore/Metadata/RuntimeTypeBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; @@ -73,13 +72,16 @@ protected RuntimeTypeBase( _indexerPropertyInfo = indexerPropertyInfo; _discriminatorValue = discriminatorValue; _isPropertyBag = propertyBag; - if(discriminatorProperty != null) { - SetAnnotation(CoreAnnotationNames.DiscriminatorProperty, discriminatorProperty); - } + if (discriminatorProperty != null) + { + SetAnnotation(CoreAnnotationNames.DiscriminatorProperty, discriminatorProperty); + } + _properties = new Utilities.OrderedDictionary(propertyCount, new PropertyNameComparer(this)); if (complexPropertyCount > 0) { - _complexProperties = new Utilities.OrderedDictionary(complexPropertyCount, StringComparer.Ordinal); + _complexProperties = + new Utilities.OrderedDictionary(complexPropertyCount, StringComparer.Ordinal); } } @@ -174,13 +176,13 @@ protected virtual IEnumerable GetDerivedTypes() /// A value indicating whether this property is used as a concurrency token. /// A value indicating when a value for this property will be generated by the database. /// - /// A value indicating whether or not this property can be modified before the entity is saved to the database. + /// A value indicating whether this property can be modified before the entity is saved to the database. /// /// - /// A value indicating whether or not this property can be modified after the entity is saved to the database. + /// A value indicating whether this property can be modified after the entity is saved to the database. /// /// The maximum length of data that is allowed in this property. - /// A value indicating whether or not the property can persist Unicode characters. + /// A value indicating whether the property can persist Unicode characters. /// The precision of data that is allowed in this property. /// The scale of data that is allowed in this property. /// @@ -286,7 +288,7 @@ public virtual IEnumerable GetDeclaredProperties() private IEnumerable GetDerivedProperties() => !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : GetDerivedTypes().SelectMany(et => et.GetDeclaredProperties()); /// @@ -328,7 +330,7 @@ private IEnumerable FindDerivedProperties(string propertyName) Check.NotNull(propertyName); return !HasDirectlyDerivedTypes - ? Enumerable.Empty() + ? [] : (IEnumerable)GetDerivedTypes() .Select(et => et.FindDeclaredProperty(propertyName)).Where(p => p != null); } @@ -849,12 +851,12 @@ IEnumerable IReadOnlyTypeBase.GetDerivedTypesInclusive() /// [DebuggerStepThrough] IEnumerable IReadOnlyTypeBase.GetDirectlyDerivedTypes() - => DirectlyDerivedTypes.Cast(); + => DirectlyDerivedTypes; /// [DebuggerStepThrough] IEnumerable ITypeBase.GetDirectlyDerivedTypes() - => DirectlyDerivedTypes.Cast(); + => DirectlyDerivedTypes; /// bool IReadOnlyTypeBase.HasSharedClrType @@ -1076,4 +1078,3 @@ IEnumerable ITypeBase.GetFlattenedComplexProperties() IEnumerable ITypeBase.GetFlattenedDeclaredProperties() => GetFlattenedDeclaredProperties(); } - diff --git a/src/EFCore/Metadata/ServiceParameterBinding.cs b/src/EFCore/Metadata/ServiceParameterBinding.cs index b6ff5e7cec6..c61fb2d8960 100644 --- a/src/EFCore/Metadata/ServiceParameterBinding.cs +++ b/src/EFCore/Metadata/ServiceParameterBinding.cs @@ -15,8 +15,6 @@ namespace Microsoft.EntityFrameworkCore.Metadata; /// public abstract class ServiceParameterBinding : ParameterBinding { - private Func? _serviceDelegate; - /// /// Creates a new instance for the given service type /// or metadata type. @@ -73,9 +71,10 @@ public abstract Expression BindToParameter( /// /// A delegate to set a CLR service property on an entity instance. /// + [field: AllowNull, MaybeNull] public virtual Func ServiceDelegate => NonCapturingLazyInitializer.EnsureInitialized( - ref _serviceDelegate, this, static b => + ref field, this, static b => { var materializationContextParam = Expression.Parameter(typeof(MaterializationContext)); var entityTypeParam = Expression.Parameter(typeof(IEntityType)); diff --git a/src/EFCore/Metadata/ServiceParameterBindingFactory.cs b/src/EFCore/Metadata/ServiceParameterBindingFactory.cs index 2a70b6f7830..259109642cb 100644 --- a/src/EFCore/Metadata/ServiceParameterBindingFactory.cs +++ b/src/EFCore/Metadata/ServiceParameterBindingFactory.cs @@ -30,7 +30,7 @@ public ServiceParameterBindingFactory(Type serviceType) => _serviceType = serviceType; /// - /// Checks whether or not this factory can bind a parameter with the given type and name. + /// Checks whether this factory can bind a parameter with the given type and name. /// /// The parameter type. /// The parameter name. diff --git a/src/EFCore/ModelBuilder.cs b/src/EFCore/ModelBuilder.cs index 5e912e6a1a3..1bfd2473303 100644 --- a/src/EFCore/ModelBuilder.cs +++ b/src/EFCore/ModelBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore; @@ -505,10 +504,9 @@ public virtual ModelBuilder ApplyConfigurationsFromAssembly( { var applyEntityConfigurationMethod = typeof(ModelBuilder) .GetMethods() - .Single( - e => e is { Name: nameof(ApplyConfiguration), ContainsGenericParameters: true } - && e.GetParameters().SingleOrDefault()?.ParameterType.GetGenericTypeDefinition() - == typeof(IEntityTypeConfiguration<>)); + .Single(e => e is { Name: nameof(ApplyConfiguration), ContainsGenericParameters: true } + && e.GetParameters().SingleOrDefault()?.ParameterType.GetGenericTypeDefinition() + == typeof(IEntityTypeConfiguration<>)); var logger = Builder.Metadata.ScopedModelDependencies?.Logger; var foundOne = false; diff --git a/src/EFCore/Query/ExpressionPrinter.cs b/src/EFCore/Query/ExpressionPrinter.cs index bb80ed408d0..17bac15fb95 100644 --- a/src/EFCore/Query/ExpressionPrinter.cs +++ b/src/EFCore/Query/ExpressionPrinter.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.EntityFrameworkCore.Query; @@ -407,7 +406,7 @@ protected override Expression VisitBlock(BlockExpression blockExpression) } var expressions = blockExpression.Expressions.Count > 0 - ? blockExpression.Expressions.Except(new[] { blockExpression.Result }) + ? blockExpression.Expressions.Except([blockExpression.Result]) : blockExpression.Expressions; foreach (var expression in expressions) diff --git a/src/EFCore/Query/ILiftableConstantFactory.cs b/src/EFCore/Query/ILiftableConstantFactory.cs index cbb91d50c8f..6c2f41d186e 100644 --- a/src/EFCore/Query/ILiftableConstantFactory.cs +++ b/src/EFCore/Query/ILiftableConstantFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// diff --git a/src/EFCore/Query/ILiftableConstantProcessor.cs b/src/EFCore/Query/ILiftableConstantProcessor.cs index 13fee27c7a2..0ded540dbfc 100644 --- a/src/EFCore/Query/ILiftableConstantProcessor.cs +++ b/src/EFCore/Query/ILiftableConstantProcessor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// diff --git a/src/EFCore/Query/IQueryCompilationContextFactory.cs b/src/EFCore/Query/IQueryCompilationContextFactory.cs index 83f9c5d732f..227ab7a207a 100644 --- a/src/EFCore/Query/IQueryCompilationContextFactory.cs +++ b/src/EFCore/Query/IQueryCompilationContextFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// diff --git a/src/EFCore/Query/IStructuralTypeMaterializerSource.cs b/src/EFCore/Query/IStructuralTypeMaterializerSource.cs index c7443edef1a..9182bf62ece 100644 --- a/src/EFCore/Query/IStructuralTypeMaterializerSource.cs +++ b/src/EFCore/Query/IStructuralTypeMaterializerSource.cs @@ -98,4 +98,3 @@ public interface IStructuralTypeMaterializerSource /// [Obsolete("This interface has been obsoleted, use IStructuralTypeMaterializerSource instead.", error: true)] public interface IEntityMaterializerSource; - diff --git a/src/EFCore/Query/Internal/EntityQueryProvider.cs b/src/EFCore/Query/Internal/EntityQueryProvider.cs index 8f4b5a9ae85..58b33327daf 100644 --- a/src/EFCore/Query/Internal/EntityQueryProvider.cs +++ b/src/EFCore/Query/Internal/EntityQueryProvider.cs @@ -11,8 +11,6 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal; /// public class EntityQueryProvider : IAsyncQueryProvider { - private static MethodInfo? _genericCreateQueryMethod; - private MethodInfo? _genericExecuteMethod; private readonly IQueryCompiler _queryCompiler; /// @@ -24,12 +22,14 @@ public class EntityQueryProvider : IAsyncQueryProvider public EntityQueryProvider(IQueryCompiler queryCompiler) => _queryCompiler = queryCompiler; + [field: AllowNull, MaybeNull] private static MethodInfo GenericCreateQueryMethod - => _genericCreateQueryMethod ??= typeof(EntityQueryProvider) + => field ??= typeof(EntityQueryProvider) .GetMethod("CreateQuery", 1, BindingFlags.Instance | BindingFlags.Public, null, [typeof(Expression)], null)!; + [field: AllowNull, MaybeNull] private MethodInfo GenericExecuteMethod - => _genericExecuteMethod ??= _queryCompiler.GetType() + => field ??= _queryCompiler.GetType() .GetMethod("Execute", 1, BindingFlags.Instance | BindingFlags.Public, null, [typeof(Expression)], null)!; /// diff --git a/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs b/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs index afb319d52c0..656ac41eee5 100644 --- a/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs +++ b/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs @@ -3,7 +3,6 @@ using System.Buffers; using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using static System.Linq.Expressions.Expression; using ElementInit = System.Linq.Expressions.ElementInit; @@ -69,7 +68,7 @@ public class ExpressionTreeFuncletizer : ExpressionVisitor /// does need to get evaluated. This list contains instances for that case, to allow /// evaluatability. /// - private readonly HashSet _evaluatableParameters = new(); + private readonly HashSet _evaluatableParameters = []; /// /// A cache of tree fragments that have already been parameterized, along with their parameter. This allows us to reuse the same @@ -80,7 +79,7 @@ public class ExpressionTreeFuncletizer : ExpressionVisitor /// /// A set of the names of parameters that have already been created. Used to ensure different parameters have unique names. /// - private readonly HashSet _parameterNames = new(); + private readonly HashSet _parameterNames = []; /// /// Used only when evaluating arbitrary QueryRootExpressions (specifically SqlQueryRootExpression), to force any evaluatable nested @@ -250,7 +249,7 @@ public virtual void ResetPathCalculation() { ExpressionType = state.ExpressionType!, ParameterName = parameterName, - Children = Array.Empty() + Children = [] } }; } @@ -288,7 +287,7 @@ public virtual void ResetPathCalculation() { ExpressionType = state.ExpressionType!, ParameterName = parameterName, - Children = Array.Empty() + Children = [] } }; } @@ -479,7 +478,7 @@ protected override Expression VisitBinary(BinaryExpression binary) if (rightState.ContainsEvaluatable) { - children ??= new List(); + children ??= []; children.Add(rightState.Path! with { PathFromParent = static e => Property(e, nameof(BinaryExpression.Right)) }); } } @@ -560,21 +559,21 @@ protected override Expression VisitConditional(ConditionalExpression conditional { if (testState.ContainsEvaluatable) { - children ??= new List(); + children ??= []; children.Add( testState.Path! with { PathFromParent = static e => Property(e, nameof(ConditionalExpression.Test)) }); } if (ifTrueState.ContainsEvaluatable) { - children ??= new List(); + children ??= []; children.Add( ifTrueState.Path! with { PathFromParent = static e => Property(e, nameof(ConditionalExpression.IfTrue)) }); } if (ifFalseState.ContainsEvaluatable) { - children ??= new List(); + children ??= []; children.Add( ifFalseState.Path! with { PathFromParent = static e => Property(e, nameof(ConditionalExpression.IfFalse)) }); } @@ -844,7 +843,7 @@ protected override Expression VisitLambda(Expression lambda) { _state = State.CreateContainsEvaluatable( typeof(LambdaExpression), - [_state.Path! with { PathFromParent = static e => Property(e, nameof(Expression.Body)) }]); + [_state.Path! with { PathFromParent = static e => Property(e, nameof(Expression<>.Body)) }]); } _inLambda = oldInLambda; @@ -958,7 +957,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall) } // EF.MultipleParameters is defined in Relational, hence the hardcoded values here. - if (method is { Name: "MultipleParameters", DeclaringType.FullName: "Microsoft.EntityFrameworkCore.EFExtensions" }) + if (method is { Name: "MultipleParameters", DeclaringType.FullName: "Microsoft.EntityFrameworkCore.EFExtensions" }) { return HandleParameter(methodCall, "EF.MultipleParameters"); } @@ -974,7 +973,8 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall) // it's null. case nameof(MemoryExtensions.Contains) when methodCall.Arguments is [var spanArg, var valueArg, ..] - && (methodCall.Arguments.Count is 2 || methodCall.Arguments.Count is 3 && methodCall.Arguments[2] is ConstantExpression { Value: null }) + && (methodCall.Arguments.Count is 2 + || methodCall.Arguments.Count is 3 && methodCall.Arguments[2] is ConstantExpression { Value: null }) && TryUnwrapSpanImplicitCast(spanArg, out var unwrappedSpanArg): { return Visit( @@ -1961,7 +1961,7 @@ private static StateType CombineStateTypes(StateType stateType1, StateType state { ExpressionType = state.ExpressionType!, ParameterName = parameterName, - Children = Array.Empty() + Children = [] } }; @@ -2097,6 +2097,7 @@ bool PreserveConvertNode(Expression expression) { parameterName = originalParameterName + i; } + _parameterNames.Add(parameterName); } else diff --git a/src/EFCore/Query/Internal/IQueryCompiler.cs b/src/EFCore/Query/Internal/IQueryCompiler.cs index 277a351417a..aa3d914a972 100644 --- a/src/EFCore/Query/Internal/IQueryCompiler.cs +++ b/src/EFCore/Query/Internal/IQueryCompiler.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query.Internal; /// diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index f8c62d0d5d5..4cb34b51615 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using ExpressionExtensions = Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions; @@ -59,14 +58,14 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp { source = Visit(source); return TryExpandRelationship(source, MemberIdentity.Create(navigationName)) - ?? methodCallExpression.Update(null, new[] { source, methodCallExpression.Arguments[1] }); + ?? methodCallExpression.Update(null, [source, methodCallExpression.Arguments[1]]); } if (methodCallExpression.TryGetIndexerArguments(Model, out source, out navigationName)) { source = Visit(source); return TryExpandRelationship(source, MemberIdentity.Create(navigationName)) - ?? methodCallExpression.Update(source, new[] { methodCallExpression.Arguments[0] }); + ?? methodCallExpression.Update(source, [methodCallExpression.Arguments[0]]); } return base.VisitMethodCall(methodCallExpression); @@ -428,13 +427,12 @@ private Expression ExpandForeignKey( var predicateBody = Expression.AndAlso( outerKey is NewArrayExpression newArrayExpression ? newArrayExpression.Expressions - .Select( - e => - { - var left = (e as UnaryExpression)?.Operand ?? e; + .Select(e => + { + var left = (e as UnaryExpression)?.Operand ?? e; - return Expression.NotEqual(left, Expression.Constant(null, left.Type)); - }) + return Expression.NotEqual(left, Expression.Constant(null, left.Type)); + }) .Aggregate(Expression.AndAlso) : Expression.NotEqual(outerKey, Expression.Constant(null, outerKey.Type)), ExpressionExtensions.CreateEqualsExpression(outerKey, innerKey)); @@ -463,7 +461,7 @@ outerKey is NewArrayExpression newArrayExpression var resultSelector = Expression.Lambda( Expression.New( resultType.GetConstructors().Single(), - new[] { resultSelectorOuterParameter, resultSelectorInnerParameter }, + [resultSelectorOuterParameter, resultSelectorInnerParameter], transparentIdentifierOuterMemberInfo, transparentIdentifierInnerMemberInfo), resultSelectorOuterParameter, @@ -641,19 +639,16 @@ protected override Expression VisitTypeBinary(TypeBinaryExpression typeBinaryExp private static IEntityType? TryGetEntityType(Expression expression) { var innerExpression = expression.UnwrapTypeConversion(out var convertedType); - if (UnwrapEntityReference(innerExpression) is EntityReference entityReference) + if (UnwrapEntityReference(innerExpression) is { } entityReference) { var entityType = entityReference.EntityType; - if (convertedType != null) + if (convertedType == null) { - entityType = entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) - .FirstOrDefault(et => et.ClrType == convertedType); - if (entityType == null) - { - return null; - } + return entityType; } + entityType = entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) + .FirstOrDefault(et => et.ClrType == convertedType); return entityType; } @@ -851,7 +846,7 @@ private Expression ExpandIncludesHelper(Expression root, EntityReference entityR Expression.Lambda( Expression.New( resultType.GetConstructors().Single(), - new[] { joinParameter, targetParameter }, + [joinParameter, targetParameter], transparentIdentifierOuterMemberInfo, transparentIdentifierInnerMemberInfo), joinParameter, @@ -925,7 +920,7 @@ private static Expression RemapFilterExpressionForJoinEntity( var method = methodCallExpression.Method.GetGenericMethodDefinition().MakeGenericMethod(genericParameters); if (arguments.Length == 2 - && arguments[1].GetLambdaOrNull() is LambdaExpression lambdaExpression) + && arguments[1].GetLambdaOrNull() is { } lambdaExpression) { arguments[1] = Expression.Quote( Expression.Lambda( @@ -1025,7 +1020,8 @@ private sealed class ReducingExpressionVisitor : ExpressionVisitor return Visit(queryablePropertyReference.Parent).CreateEFPropertyExpression(queryablePropertyReference.Property); case ComplexPropertyReference complexPropertyReference: - return Visit(complexPropertyReference.Parent).CreateEFPropertyExpression(complexPropertyReference.Property, makeNullable: false); + return Visit(complexPropertyReference.Parent).CreateEFPropertyExpression( + complexPropertyReference.Property, makeNullable: false); case IncludeExpression includeExpression: var entityExpression = Visit(includeExpression.EntityExpression); @@ -1148,8 +1144,8 @@ public GroupingElementReplacingExpressionVisitor( _keyAccessExpression = Expression.MakeMemberAccess( groupByNavigationExpansionExpression.CurrentParameter, groupByNavigationExpansionExpression.CurrentParameter.Type.GetTypeInfo().GetDeclaredProperty( - nameof(IGrouping.Key))!); - _keyMemberInfo = parameterExpression.Type.GetTypeInfo().GetDeclaredProperty(nameof(IGrouping.Key))!; + nameof(IGrouping<,>.Key))!); + _keyMemberInfo = parameterExpression.Type.GetTypeInfo().GetDeclaredProperty(nameof(IGrouping<,>.Key))!; _cloningExpressionVisitor = new CloningExpressionVisitor(); } @@ -1194,7 +1190,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp .Visit(_navigationExpansionExpression.PendingSelector), _navigationExpansionExpression.CurrentParameter.Name!); - return methodCallExpression.Update(null, new[] { navigationExpansionExpression }); + return methodCallExpression.Update(null, [navigationExpansionExpression]); } return base.VisitMethodCall(methodCallExpression); @@ -1320,7 +1316,7 @@ when methodCallExpression.TryGetEFPropertyArguments(out _, out _): default: var convertlessExpression = expression.UnwrapTypeConversion(out var convertedType); - if (UnwrapEntityReference(convertlessExpression) is EntityReference entityReference) + if (UnwrapEntityReference(convertlessExpression) is { } entityReference) { var entityType = entityReference.EntityType; if (convertedType != null) diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs index ed75f154261..bf9e1235565 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs @@ -88,10 +88,7 @@ void PrintInclude(IncludeTreeNode currentNode) private sealed class IncludeTreeNode(IEntityType entityType, EntityReference? reference, bool setLoaded) : Dictionary { - public IncludeTreeNode(IEntityType entityType) - : this(entityType, null, setLoaded: true) - { - } + private EntityReference? _reference = reference; public IEntityType EntityType { get; } = entityType; public LambdaExpression? FilterExpression { get; private set; } @@ -110,25 +107,21 @@ public IncludeTreeNode AddNavigation(INavigationBase navigation, bool setLoaded) } IncludeTreeNode? nodeToAdd = null; - if (reference != null) + if (_reference != null) { - if (navigation is INavigation concreteNavigation - && reference.ForeignKeyExpansionMap.TryGetValue( - (concreteNavigation.ForeignKey, concreteNavigation.IsOnDependent), out var expansion)) - { - // Value known to be non-null - nodeToAdd = UnwrapEntityReference(expansion)!.IncludePaths; - } - else if (navigation is ISkipNavigation skipNavigation - && reference.ForeignKeyExpansionMap.TryGetValue( - (skipNavigation.ForeignKey, skipNavigation.IsOnDependent), out var firstExpansion) - // Value known to be non-null - && UnwrapEntityReference(firstExpansion)!.ForeignKeyExpansionMap.TryGetValue( - (skipNavigation.Inverse.ForeignKey, !skipNavigation.Inverse.IsOnDependent), out var secondExpansion)) + nodeToAdd = navigation switch { - // Value known to be non-null - nodeToAdd = UnwrapEntityReference(secondExpansion)!.IncludePaths; - } + INavigation concreteNavigation when _reference.ForeignKeyExpansionMap.TryGetValue( + (concreteNavigation.ForeignKey, concreteNavigation.IsOnDependent), out var expansion) => UnwrapEntityReference( + expansion)!.IncludePaths, + ISkipNavigation skipNavigation when _reference.ForeignKeyExpansionMap.TryGetValue( + (skipNavigation.ForeignKey, skipNavigation.IsOnDependent), out var firstExpansion) + // Value known to be non-null + && UnwrapEntityReference(firstExpansion)!.ForeignKeyExpansionMap.TryGetValue( + (skipNavigation.Inverse.ForeignKey, !skipNavigation.Inverse.IsOnDependent), + out var secondExpansion) => UnwrapEntityReference(secondExpansion)!.IncludePaths, + _ => nodeToAdd + }; } nodeToAdd ??= new IncludeTreeNode(navigation.TargetEntityType, null, setLoaded); @@ -161,7 +154,7 @@ public void Merge(IncludeTreeNode includeTreeNode) } public void AssignEntityReference(EntityReference entityReference) - => reference = entityReference; + => _reference = entityReference; public void ApplyFilter(LambdaExpression filterExpression) => FilterExpression = filterExpression; @@ -205,8 +198,6 @@ private sealed class NavigationExpansionExpression : Expression, IPrintableExpre private readonly string _parameterName; - private NavigationTreeNode? _currentTree; - public NavigationExpansionExpression( Expression source, NavigationTreeNode currentTree, @@ -225,14 +216,15 @@ public ParameterExpression CurrentParameter // CurrentParameter would be non-null if CurrentTree is non-null => CurrentTree.CurrentParameter!; + [field: AllowNull, MaybeNull] public NavigationTreeNode CurrentTree { // _currentTree is always non-null. Field is to override the setter to set parameter - get => _currentTree!; + get; private set { - _currentTree = value; - _currentTree.SetParameter(_parameterName); + field = value; + field.SetParameter(_parameterName); } } diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs index 41bc9f06e5d..39e6d83cdbf 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; using ExpressionExtensions = Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions; @@ -270,8 +269,11 @@ protected override Expression VisitMember(MemberExpression memberExpression) var innerExpression = Visit(memberExpression.Expression); // Handler access of a complex collection property over a complex non-collection property - if (memberExpression.Expression is ComplexPropertyReference { Property: { IsCollection: false } complexProperty } complexPropertyReference - && complexProperty.ComplexType.FindComplexProperty(memberExpression.Member) is IComplexProperty nestedComplexProperty) + if (memberExpression.Expression is ComplexPropertyReference + { + Property: { IsCollection: false } complexProperty + } complexPropertyReference + && complexProperty.ComplexType.FindComplexProperty(memberExpression.Member) is { } nestedComplexProperty) { return new ComplexPropertyReference(complexPropertyReference, nestedComplexProperty); } @@ -279,13 +281,12 @@ protected override Expression VisitMember(MemberExpression memberExpression) // Convert ICollection.Count to Count() if (memberExpression.Expression != null && innerExpression != null - && memberExpression.Member.Name == nameof(ICollection.Count) + && memberExpression.Member.Name == nameof(ICollection<>.Count) && memberExpression.Expression.Type.GetInterfaces().Append(memberExpression.Expression.Type) - .Any( - e => e.IsGenericType - && (e.GetGenericTypeDefinition() is Type genericTypeDefinition - && (genericTypeDefinition == typeof(ICollection<>) - || genericTypeDefinition == typeof(IReadOnlyCollection<>))))) + .Any(e => e.IsGenericType + && (e.GetGenericTypeDefinition() is var genericTypeDefinition + && (genericTypeDefinition == typeof(ICollection<>) + || genericTypeDefinition == typeof(IReadOnlyCollection<>))))) { var innerQueryable = UnwrapCollectionMaterialization(innerExpression); @@ -835,7 +836,7 @@ when QueryableMethods.IsSumWithSelector(method): || method.GetGenericMethodDefinition() == EnumerableMethods.ToArray)) { return methodCallExpression.Update( - null, new[] { UnwrapCollectionMaterialization(Visit(methodCallExpression.Arguments[0])) }); + null, [UnwrapCollectionMaterialization(Visit(methodCallExpression.Arguments[0]))]); } return ProcessUnknownMethod(methodCallExpression); @@ -856,7 +857,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) { var innerQueryable = UnwrapCollectionMaterialization(operand); // Only if inner is queryable as array properties could also have Length access - if (innerQueryable.Type.TryGetElementType(typeof(IQueryable<>)) is Type elementType) + if (innerQueryable.Type.TryGetElementType(typeof(IQueryable<>)) is { } elementType) { return Visit(Expression.Call(QueryableMethods.CountWithoutPredicate.MakeGenericMethod(elementType), innerQueryable)); } @@ -928,7 +929,7 @@ private NavigationExpansionExpression ProcessCastOfType( if (newStructure is EntityReference entityReference && entityReference.EntityType.GetAllBaseTypes().Concat(entityReference.EntityType.GetDerivedTypesInclusive()) - .FirstOrDefault(et => et.ClrType == castType) is IEntityType castEntityType) + .FirstOrDefault(et => et.ClrType == castType) is { } castEntityType) { var newEntityReference = new EntityReference(castEntityType, entityReference.EntityQueryRootExpression); if (entityReference.IsOptional) @@ -940,9 +941,8 @@ private NavigationExpansionExpression ProcessCastOfType( // Prune includes for sibling types var siblingNavigations = newEntityReference.IncludePaths.Keys - .Where( - n => !castEntityType.IsAssignableFrom(n.DeclaringEntityType) - && !n.DeclaringEntityType.IsAssignableFrom(castEntityType)); + .Where(n => !castEntityType.IsAssignableFrom(n.DeclaringEntityType) + && !n.DeclaringEntityType.IsAssignableFrom(castEntityType)); foreach (var navigation in siblingNavigations) { @@ -1405,7 +1405,7 @@ private NavigationExpansionExpression ProcessSelectMany( var newResultSelector = Expression.Lambda( Expression.New( transparentIdentifierType.GetConstructors().Single(), - new[] { source.CurrentParameter, collectionElementParameter }, transparentIdentifierOuterMemberInfo, + [source.CurrentParameter, collectionElementParameter], transparentIdentifierOuterMemberInfo, transparentIdentifierInnerMemberInfo), source.CurrentParameter, collectionElementParameter); @@ -1421,8 +1421,8 @@ private NavigationExpansionExpression ProcessSelectMany( var pendingSelector = resultSelector == null ? innerTree : new ReplacingExpressionVisitor( - new Expression[] { resultSelector.Parameters[0], resultSelector.Parameters[1] }, - new[] { source.PendingSelector, innerTree }) + [resultSelector.Parameters[0], resultSelector.Parameters[1]], + [source.PendingSelector, innerTree]) .Visit(resultSelector.Body); var parameterName = GetParameterName("ti"); @@ -1743,15 +1743,18 @@ private IReadOnlyCollection GetApplicableQueryFilters(IEntityType ? [] : _queryCompilationContext.IgnoredQueryFilters == null ? entityType.GetDeclaredQueryFilters() - : [.. entityType.GetDeclaredQueryFilters() - .Where(filter => filter != null && (filter.IsAnonymous || !_queryCompilationContext.IgnoredQueryFilters.Contains(filter.Key)))]; + : + [ + .. entityType.GetDeclaredQueryFilters() + .Where(filter => filter != null + && (filter.IsAnonymous || !_queryCompilationContext.IgnoredQueryFilters.Contains(filter.Key))) + ]; private Expression ApplyQueryFilter(IEntityType entityType, NavigationExpansionExpression navigationExpansionExpression) { var rootEntityType = entityType.GetRootType(); var queryFilters = GetApplicableQueryFilters(rootEntityType); - if (queryFilters.Count == 0) { return navigationExpansionExpression; @@ -1771,11 +1774,12 @@ private Expression ApplyQueryFilter(IEntityType entityType, NavigationExpansionE // TODO: filter into the QueryCompilationContext.NonNullableReferenceTypeParameters tempFilterPredicate = (LambdaExpression)_funcletizer.ExtractParameters( tempFilterPredicate, _parameters, parameterize: false, clearParameterizedValues: false, - _queryCompilationContext.IsPrecompiling); + _queryCompilationContext.IsPrecompiling); if (queryFilters.Count > 1) { - tempFilterPredicate = Expression.Lambda(ReplacingExpressionVisitor.Replace(tempFilterPredicate.Parameters[0], commonParameter, tempFilterPredicate.Body)); + tempFilterPredicate = Expression.Lambda( + ReplacingExpressionVisitor.Replace(tempFilterPredicate.Parameters[0], commonParameter, tempFilterPredicate.Body)); } tempFilterPredicate = (LambdaExpression)_queryTranslationPreprocessor.NormalizeQueryableMethod(tempFilterPredicate); @@ -1789,15 +1793,15 @@ private Expression ApplyQueryFilter(IEntityType entityType, NavigationExpansionE var filterWrapper = Expression.Call( QueryableMethods.Where.MakeGenericMethod(rootEntityType.ClrType), rootExpression, - filterPredicate!); + filterPredicate!); filterPredicate = filterWrapper.Arguments[1].UnwrapLambdaFromQuote(); _parameterizedQueryFilterPredicateCache[cacheKey] = filterPredicate!; } filterPredicate = - (LambdaExpression)new SelfReferenceEntityQueryableRewritingExpressionVisitor(this, entityType).Visit( - filterPredicate!); + (LambdaExpression)new SelfReferenceEntityQueryableRewritingExpressionVisitor(this, entityType).Visit( + filterPredicate!); // if we are constructing EntityQueryable of a derived type, we need to re-map filter predicate to the correct derived type var filterPredicateParameter = filterPredicate.Parameters[0]; @@ -1862,8 +1866,8 @@ private static MethodCallExpression ConvertToEnumerable(MethodInfo queryableMeth ? queryableMethod.GetGenericArguments() : []; - var enumerableArguments = arguments.Select( - arg => arg is UnaryExpression { NodeType: ExpressionType.Quote, Operand: LambdaExpression } unaryExpression + var enumerableArguments = arguments.Select(arg + => arg is UnaryExpression { NodeType: ExpressionType.Quote, Operand: LambdaExpression } unaryExpression ? unaryExpression.Operand : arg).ToList(); @@ -2059,7 +2063,7 @@ private LambdaExpression GenerateLambda(Expression body, ParameterExpression cur private Expression UnwrapCollectionMaterialization(Expression expression) { while (expression is MethodCallExpression { Method.IsGenericMethod: true } innerMethodCall - && innerMethodCall.Method.GetGenericMethodDefinition() is MethodInfo innerMethod + && innerMethodCall.Method.GetGenericMethodDefinition() is var innerMethod && (innerMethod == EnumerableMethods.AsEnumerable || innerMethod == EnumerableMethods.ToList || innerMethod == EnumerableMethods.ToArray)) @@ -2216,7 +2220,7 @@ when methodCallExpression.TryGetEFPropertyArguments(out var entityExpression, ou break; - case MemberExpression { Expression: { } } memberExpression: + case MemberExpression { Expression: not null } memberExpression: if (TryExtractIncludeTreeNode(memberExpression.Expression, memberExpression.Member.Name, out var addedNode)) { return addedNode; diff --git a/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs b/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs index 9676f25ddc8..8482d63a307 100644 --- a/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query.Internal; /// diff --git a/src/EFCore/Query/Internal/PrecompiledQueryContext.cs b/src/EFCore/Query/Internal/PrecompiledQueryContext.cs index 8587758c602..65a1699251b 100644 --- a/src/EFCore/Query/Internal/PrecompiledQueryContext.cs +++ b/src/EFCore/Query/Internal/PrecompiledQueryContext.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore.Query.Internal; diff --git a/src/EFCore/Query/Internal/PrecompiledQueryableAsyncEnumerableAdapter.cs b/src/EFCore/Query/Internal/PrecompiledQueryableAsyncEnumerableAdapter.cs index e01894b27aa..bb9e316bda0 100644 --- a/src/EFCore/Query/Internal/PrecompiledQueryableAsyncEnumerableAdapter.cs +++ b/src/EFCore/Query/Internal/PrecompiledQueryableAsyncEnumerableAdapter.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.EntityFrameworkCore.Query.Internal; diff --git a/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs b/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs index b11e67319af..e47392387b2 100644 --- a/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs +++ b/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query.Internal; /// diff --git a/src/EFCore/Query/Internal/QueryCompiler.cs b/src/EFCore/Query/Internal/QueryCompiler.cs index 02e1984dfa2..c4df4b66531 100644 --- a/src/EFCore/Query/Internal/QueryCompiler.cs +++ b/src/EFCore/Query/Internal/QueryCompiler.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.EntityFrameworkCore.Query.Internal; diff --git a/src/EFCore/Query/Internal/QueryFiltersCacheKey.cs b/src/EFCore/Query/Internal/QueryFiltersCacheKey.cs index 59ae2bc089d..5182a0ce3af 100644 --- a/src/EFCore/Query/Internal/QueryFiltersCacheKey.cs +++ b/src/EFCore/Query/Internal/QueryFiltersCacheKey.cs @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + namespace Microsoft.EntityFrameworkCore.Query.Internal; /// @@ -13,7 +14,8 @@ public class QueryFiltersCacheKey(IEntityType entityType, IReadOnlyCollection Keys => field ??= [.. queryFilters.Select(x => x.Key)]; + private HashSet Keys + => field ??= [.. queryFilters.Select(x => x.Key)]; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -21,8 +23,8 @@ public class QueryFiltersCacheKey(IEntityType entityType, IReadOnlyCollection - public bool Equals(QueryFiltersCacheKey? other) => - ReferenceEquals(_entityType, other?._entityType) + public bool Equals(QueryFiltersCacheKey? other) + => ReferenceEquals(_entityType, other?._entityType) && Keys.Count == other.Keys.Count && Keys.All(other.Keys.Contains); @@ -34,6 +36,7 @@ private static int CalculateHashCode(IEntityType entityType, IReadOnlyCollection { hashCode.Add(filter.Key); } + return hashCode.ToHashCode(); } @@ -43,7 +46,8 @@ private static int CalculateHashCode(IEntityType entityType, IReadOnlyCollection /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override bool Equals(object? obj) => obj is QueryFiltersCacheKey other && Equals(other); + public override bool Equals(object? obj) + => obj is QueryFiltersCacheKey other && Equals(other); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -51,5 +55,6 @@ private static int CalculateHashCode(IEntityType entityType, IReadOnlyCollection /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override int GetHashCode() => _hashCode; + public override int GetHashCode() + => _hashCode; } diff --git a/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs b/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs index 030663bfdcc..14941b56bad 100644 --- a/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Query.Internal; @@ -157,7 +156,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp // Normalize x.Any(i => i == foo) to x.Contains(foo) // And x.All(i => i != foo) to !x.Contains(foo) if (methodCallExpression.Method.IsGenericMethod - && methodCallExpression.Method.GetGenericMethodDefinition() is MethodInfo methodInfo + && methodCallExpression.Method.GetGenericMethodDefinition() is var methodInfo && (methodInfo == EnumerableMethods.AnyWithPredicate || methodInfo == EnumerableMethods.All || methodInfo == QueryableMethods.AnyWithPredicate @@ -357,7 +356,7 @@ when unaryExpression.IsLogicalNot(): // Simplify (a != null ? new { Member = b, ... } : null).Member // to a != null ? b : null // Later null check removal will simplify it further - if (expression is MemberExpression { Expression: Expression inner } visitedMemberExpression) + if (expression is MemberExpression { Expression: { } inner } visitedMemberExpression) { var (conditional, convert) = inner switch { @@ -374,7 +373,7 @@ when unaryExpression.IsLogicalNot(): Test: BinaryExpression { NodeType: ExpressionType.Equal or ExpressionType.NotEqual } binaryTest } conditionalExpression && !(conditionalExpression.Type.IsNullableValueType() - && visitedMemberExpression.Member.Name is nameof(Nullable.HasValue) or nameof(Nullable.Value))) + && visitedMemberExpression.Member.Name is nameof(Nullable<>.HasValue) or nameof(Nullable<>.Value))) { var isLeftNullConstant = IsNullConstant(binaryTest.Left); var isRightNullConstant = IsNullConstant(binaryTest.Right); diff --git a/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs b/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs index 80dbb37f040..e15dbc5b400 100644 --- a/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Collections.ObjectModel; using ExpressionExtensions = Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions; namespace Microsoft.EntityFrameworkCore.Query.Internal; @@ -64,19 +63,19 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) NodeType: ExpressionType.GreaterThan or ExpressionType.NotEqual, Left: MemberExpression { - Member: { Name: nameof(ICollection.Count), DeclaringType.IsGenericType: true } member, - Expression: Expression source + Member: { Name: nameof(ICollection<>.Count), DeclaringType.IsGenericType: true } member, + Expression: { } source }, Right: ConstantExpression { Value: 0 } } - when member.DeclaringType.GetGenericTypeDefinition() is Type genericTypeDefinition - && (genericTypeDefinition == typeof(ICollection<>) - || genericTypeDefinition.GetInterfaces() - .Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>))) - => VisitMethodCall( - Expression.Call( - EnumerableMethods.AnyWithoutPredicate.MakeGenericMethod(source.Type.GetSequenceType()), - source)), + when member.DeclaringType.GetGenericTypeDefinition() is var genericTypeDefinition + && (genericTypeDefinition == typeof(ICollection<>) + || genericTypeDefinition.GetInterfaces() + .Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>))) + => VisitMethodCall( + Expression.Call( + EnumerableMethods.AnyWithoutPredicate.MakeGenericMethod(source.Type.GetSequenceType()), + source)), // Same for arrays: convert x.Length > 0 and x.Length != 0 to x.Any() { @@ -84,14 +83,14 @@ when member.DeclaringType.GetGenericTypeDefinition() is Type genericTypeDefiniti Left: UnaryExpression { NodeType: ExpressionType.ArrayLength, - Operand: Expression source + Operand: { } source }, Right: ConstantExpression { Value: 0 } } - => VisitMethodCall( - Expression.Call( - EnumerableMethods.AnyWithoutPredicate.MakeGenericMethod(source.Type.GetSequenceType()), - source)), + => VisitMethodCall( + Expression.Call( + EnumerableMethods.AnyWithoutPredicate.MakeGenericMethod(source.Type.GetSequenceType()), + source)), _ => base.VisitBinary(binaryExpression) }; @@ -109,7 +108,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp // Extract information from query metadata method and prune them if (method.DeclaringType == typeof(EntityFrameworkQueryableExtensions) && method.IsGenericMethod - && ExtractQueryMetadata(methodCallExpression) is Expression expression) + && ExtractQueryMetadata(methodCallExpression) is { } expression) { return expression; } @@ -151,9 +150,9 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp { Name: "get_Item", IsStatic: false, - DeclaringType: Type declaringType + DeclaringType: { } declaringType }, - Object: Expression indexerSource, + Object: { } indexerSource, Arguments: [var index] } && declaringType.GetInterface("IReadOnlyList`1") is not null) @@ -173,14 +172,14 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp if (method.DeclaringType is { IsGenericType: true } && method.DeclaringType.TryGetElementType(typeof(ICollection<>)) is not null - && method.Name == nameof(ICollection.Contains)) + && method.Name == nameof(ICollection<>.Contains)) { visitedExpression = TryConvertCollectionContainsToQueryableContains(methodCallExpression); } if (method.DeclaringType == typeof(EntityFrameworkQueryableExtensions) && method.IsGenericMethod - && method.GetGenericMethodDefinition() is MethodInfo genericMethod + && method.GetGenericMethodDefinition() is var genericMethod && (genericMethod == EntityFrameworkQueryableExtensions.IncludeMethodInfo || genericMethod == EntityFrameworkQueryableExtensions.ThenIncludeAfterEnumerableMethodInfo || genericMethod == EntityFrameworkQueryableExtensions.ThenIncludeAfterReferenceMethodInfo @@ -212,7 +211,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp return Expression.Call(newIncludeMethod, source, lambda); } - return methodCallExpression.Update(null, new[] { source, lambda }); + return methodCallExpression.Update(null, [source, lambda]); } } @@ -501,8 +500,7 @@ private Expression TryConvertEnumerableToQueryable(MethodCallExpression methodCa { return Expression.Call( queryableMethod, - arguments.Select( - arg => arg is LambdaExpression lambda ? Expression.Quote(lambda) : arg)); + arguments.Select(arg => arg is LambdaExpression lambda ? Expression.Quote(lambda) : arg)); } } @@ -592,7 +590,7 @@ private MethodCallExpression TryFlattenGroupJoinSelectMany(MethodCallExpression ] selectManyArguments } when selectManyMethod.GetGenericMethodDefinition() == QueryableMethods.SelectManyWithCollectionSelector - && groupJoinMethod.GetGenericMethodDefinition() == QueryableMethods.GroupJoin: + && groupJoinMethod.GetGenericMethodDefinition() == QueryableMethods.GroupJoin: { var outer = groupJoinArguments[0]; var inner = groupJoinArguments[1]; @@ -703,7 +701,7 @@ when selectManyMethod.GetGenericMethodDefinition() == QueryableMethods.SelectMan ] selectManyArguments } when selectManyMethod.GetGenericMethodDefinition() == QueryableMethods.SelectManyWithoutCollectionSelector - && groupJoinMethod.GetGenericMethodDefinition() == QueryableMethods.GroupJoin: + && groupJoinMethod.GetGenericMethodDefinition() == QueryableMethods.GroupJoin: { var outer = groupJoinArguments[0]; var inner = groupJoinArguments[1]; @@ -787,8 +785,8 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp } Expression correlationPredicate; - if (outerKeySelector.Body is NewExpression { Arguments: ReadOnlyCollection outerArguments } - && innerKeySelector.Body is NewExpression { Arguments: ReadOnlyCollection innerArguments } + if (outerKeySelector.Body is NewExpression { Arguments: { } outerArguments } + && innerKeySelector.Body is NewExpression { Arguments: { } innerArguments } && outerArguments.Count == innerArguments.Count && outerArguments.Count > 0) { @@ -796,8 +794,10 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp Expression? outerEqualsInner = null; for (var i = 0; i < outerArguments.Count; i++) { - var outerArgumentNotEqualsNull = ExpressionExtensions.CreateEqualsExpression(outerArguments[i], Expression.Constant(null), negated: true); - var outerArgumentEqualsInnerArgument = ExpressionExtensions.CreateEqualsExpression(outerArguments[i], innerArguments[i]); + var outerArgumentNotEqualsNull = ExpressionExtensions.CreateEqualsExpression( + outerArguments[i], Expression.Constant(null), negated: true); + var outerArgumentEqualsInnerArgument = + ExpressionExtensions.CreateEqualsExpression(outerArguments[i], innerArguments[i]); if (i == 0) { diff --git a/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs b/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs index 5c98ed229d9..040ac24b656 100644 --- a/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs +++ b/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs @@ -98,8 +98,9 @@ public Expression CreateMaterializeExpression( var materializationExpression = HandleMaterializationInterception(); return - structuralType is IComplexType complexType && ReadComplexTypeDirectly(complexType) - && (IsNullable(complexType) || parameters.AllowNullable == true) + structuralType is IComplexType complexType + && ReadComplexTypeDirectly(complexType) + && (IsNullable(complexType) || parameters.AllowNullable == true) ? HandleNullableComplexTypeMaterialization( complexType, complexType.ClrType, @@ -115,17 +116,17 @@ Expression HandleMaterializationInterception() // TODO: This currently applies the materialization interceptor only on the root structural type - any contained complex types // don't get intercepted. #35883 || structuralType is not IEntityType - ? properties.Count == 0 && blockExpressions.Count == 0 - ? constructorExpression - : CreateMaterializeExpression(blockExpressions, instanceVariable, constructorExpression, properties, bindingInfo) - : CreateInterceptionMaterializeExpression( - structuralType, - properties, - _materializationInterceptor, - bindingInfo, - constructorExpression, - instanceVariable, - blockExpressions); + ? properties.Count == 0 && blockExpressions.Count == 0 + ? constructorExpression + : CreateMaterializeExpression(blockExpressions, instanceVariable, constructorExpression, properties, bindingInfo) + : CreateInterceptionMaterializeExpression( + structuralType, + properties, + _materializationInterceptor, + bindingInfo, + constructorExpression, + instanceVariable, + blockExpressions); } } @@ -133,7 +134,8 @@ Expression HandleMaterializationInterception() /// Should complex type be read directly using e.g. DbDataReader.GetFieldValue /// or is it going to be handled separately (i.e. relational JSON). /// - protected virtual bool ReadComplexTypeDirectly(IComplexType complexType) => true; + protected virtual bool ReadComplexTypeDirectly(IComplexType complexType) + => true; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -199,7 +201,7 @@ static Expression CreateMemberAssignment(Expression parameter, MemberInfo member ReferenceEqual(value, Constant(null))), MakeMemberAccess( currentVariable, - iCollectionInterface.GetProperty(nameof(ICollection.IsReadOnly))!)), + iCollectionInterface.GetProperty(nameof(ICollection<>.IsReadOnly))!)), MakeMemberAccess(parameter, memberInfo).Assign(value), Call( genericMethod, @@ -219,7 +221,8 @@ static Expression CreateMemberAssignment(Expression parameter, MemberInfo member Expression CreateComplexTypeMaterializeExpression(IComplexProperty complexProperty, ParameterBindingInfo bindingInfo) { var materializeExpression = CreateMaterializeExpression( - new StructuralTypeMaterializerSourceParameters(complexProperty.ComplexType, "complexType", null, QueryTrackingBehavior: null), + new StructuralTypeMaterializerSourceParameters( + complexProperty.ComplexType, "complexType", null, QueryTrackingBehavior: null), bindingInfo.MaterializationContextExpression); return IsNullable(complexProperty) @@ -309,17 +312,17 @@ private static readonly MethodInfo InitializedInstanceMethod = typeof(IMaterializationInterceptor).GetMethod(nameof(IMaterializationInterceptor.InitializedInstance))!; private static readonly PropertyInfo HasResultMethod - = typeof(InterceptionResult).GetProperty(nameof(InterceptionResult.HasResult))!; + = typeof(InterceptionResult).GetProperty(nameof(InterceptionResult<>.HasResult))!; private static readonly PropertyInfo ResultProperty - = typeof(InterceptionResult).GetProperty(nameof(InterceptionResult.Result))!; + = typeof(InterceptionResult).GetProperty(nameof(InterceptionResult<>.Result))!; private static readonly PropertyInfo IsSuppressedProperty = typeof(InterceptionResult).GetProperty(nameof(InterceptionResult.IsSuppressed))!; private static readonly MethodInfo DictionaryAddMethod = typeof(Dictionary)>).GetMethod( - nameof(Dictionary.Add), + nameof(Dictionary<,>.Add), [typeof(IPropertyBase), typeof((object, Func))])!; private static readonly ConstructorInfo DictionaryConstructor @@ -602,7 +605,9 @@ public virtual Func GetEmptyMaterializer(IComple /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual Func GetEmptyMaterializer( - ITypeBase entityType, InstantiationBinding binding, List serviceProperties) + ITypeBase entityType, + InstantiationBinding binding, + List serviceProperties) { binding = ModifyBindings(entityType, binding); @@ -681,7 +686,11 @@ private static void CreateServiceInstances( } } - private Expression HandleNullableComplexTypeMaterialization(IComplexType complexType, Type clrType, Expression materializeExpression, ParameterBindingInfo bindingInfo) + private Expression HandleNullableComplexTypeMaterialization( + IComplexType complexType, + Type clrType, + Expression materializeExpression, + ParameterBindingInfo bindingInfo) { var valueBufferExpression = Call( bindingInfo.MaterializationContextExpression, diff --git a/src/EFCore/Query/LiftableConstantExpression.cs b/src/EFCore/Query/LiftableConstantExpression.cs index c67f1066763..b51456c73c9 100644 --- a/src/EFCore/Query/LiftableConstantExpression.cs +++ b/src/EFCore/Query/LiftableConstantExpression.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// @@ -18,8 +16,8 @@ namespace Microsoft.EntityFrameworkCore.Query; /// separately, to be assigned to a variable, and this node is replaced by a reference to that variable. /// /// -[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")] -[Experimental(EFDiagnostics.PrecompiledQueryExperimental)] +[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}"), + Experimental(EFDiagnostics.PrecompiledQueryExperimental)] public class LiftableConstantExpression : Expression, IPrintableExpression { /// diff --git a/src/EFCore/Query/LiftableConstantExpressionDependencies.cs b/src/EFCore/Query/LiftableConstantExpressionDependencies.cs index d21d5f337f9..9fcbda79cce 100644 --- a/src/EFCore/Query/LiftableConstantExpressionDependencies.cs +++ b/src/EFCore/Query/LiftableConstantExpressionDependencies.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// diff --git a/src/EFCore/Query/LiftableConstantExpressionHelpers.cs b/src/EFCore/Query/LiftableConstantExpressionHelpers.cs index 8c5a8d81522..79e51e950d3 100644 --- a/src/EFCore/Query/LiftableConstantExpressionHelpers.cs +++ b/src/EFCore/Query/LiftableConstantExpressionHelpers.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Internal; using static System.Linq.Expressions.Expression; diff --git a/src/EFCore/Query/LiftableConstantFactory.cs b/src/EFCore/Query/LiftableConstantFactory.cs index 032acf994e5..bab78308a04 100644 --- a/src/EFCore/Query/LiftableConstantFactory.cs +++ b/src/EFCore/Query/LiftableConstantFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// diff --git a/src/EFCore/Query/LiftableConstantProcessor.cs b/src/EFCore/Query/LiftableConstantProcessor.cs index 8c3ec528c55..27de6c18d6a 100644 --- a/src/EFCore/Query/LiftableConstantProcessor.cs +++ b/src/EFCore/Query/LiftableConstantProcessor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; #pragma warning disable CS1591 @@ -26,7 +24,7 @@ private sealed record LiftedConstant( Expression Expression, ParameterExpression? ReplacingParameter = null); - private readonly List _liftedConstants = new(); + private readonly List _liftedConstants = []; private readonly LiftedExpressionProcessor _liftedExpressionProcessor = new(); private readonly LiftedConstantOptimizer _liftedConstantOptimizer = new(); private ParameterExpression? _contextParameter; @@ -41,7 +39,7 @@ private sealed record LiftedConstant( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual IReadOnlyList<(ParameterExpression Parameter, Expression Expression)> LiftedConstants { get; private set; } - = Array.Empty<(ParameterExpression Parameter, Expression Expression)>(); + = []; public LiftableConstantProcessor(ShapedQueryCompilingExpressionVisitorDependencies dependencies) { @@ -335,8 +333,7 @@ public void Optimize(List liftedConstants) } Check.DebugAssert( - expressionInfo.Status == ExpressionStatus.SeenMultipleTimes, - "expressionInfo.Status == ExpressionStatus.SeenMultipleTimes"); + expressionInfo.Status == ExpressionStatus.SeenMultipleTimes); } // Second pass: extract common denominator tree fragments to separate variables @@ -436,7 +433,7 @@ public void Optimize(List liftedConstants) expressionInfo = _indexedExpressions[node] = new ExpressionInfo(ExpressionStatus.Extracted, parameter); } - Check.DebugAssert(expressionInfo.Parameter is not null, "expressionInfo.Parameter is not null"); + Check.DebugAssert(expressionInfo.Parameter is not null); return expressionInfo.Parameter; } diff --git a/src/EFCore/Query/MaterializerLiftableConstantContext.cs b/src/EFCore/Query/MaterializerLiftableConstantContext.cs index a8c062cd902..4a96cf72600 100644 --- a/src/EFCore/Query/MaterializerLiftableConstantContext.cs +++ b/src/EFCore/Query/MaterializerLiftableConstantContext.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// diff --git a/src/EFCore/Query/ParameterQueryRootExpression.cs b/src/EFCore/Query/ParameterQueryRootExpression.cs index 3c9da95da0c..38012e479b3 100644 --- a/src/EFCore/Query/ParameterQueryRootExpression.cs +++ b/src/EFCore/Query/ParameterQueryRootExpression.cs @@ -93,5 +93,6 @@ public ParameterQueryRootExpression(Type elementType, ParameterExpression parame /// This constructor has been obsoleted, use QueryParameterExpression instead. /// [Obsolete("Use QueryParameterExpression instead.")] - public virtual ParameterExpression ParameterExpression => Parameter(QueryParameterExpression.Type, QueryParameterExpression.Name); + public virtual ParameterExpression ParameterExpression + => Parameter(QueryParameterExpression.Type, QueryParameterExpression.Name); } diff --git a/src/EFCore/Query/QueryCompilationContext.cs b/src/EFCore/Query/QueryCompilationContext.cs index 88545f5ee40..af8d5e9f4ce 100644 --- a/src/EFCore/Query/QueryCompilationContext.cs +++ b/src/EFCore/Query/QueryCompilationContext.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// @@ -255,22 +253,21 @@ private Expression InsertRuntimeParameters(Expression query) ? query : Expression.Block( _runtimeParameters - .Select( - kv => - Expression.Call( - Expression.Property( - QueryContextParameter, - QueryContextParametersProperty), - ParameterDictionaryAddMethod, - Expression.Constant(kv.Key), - Expression.Convert(Expression.Invoke(kv.Value, QueryContextParameter), typeof(object)))) + .Select(kv => + Expression.Call( + Expression.Property( + QueryContextParameter, + QueryContextParametersProperty), + ParameterDictionaryAddMethod, + Expression.Constant(kv.Key), + Expression.Convert(Expression.Invoke(kv.Value, QueryContextParameter), typeof(object)))) .Append(query)); private static readonly PropertyInfo QueryContextParametersProperty = typeof(QueryContext).GetProperty(nameof(QueryContext.Parameters))!; private static readonly MethodInfo ParameterDictionaryAddMethod - = typeof(Dictionary).GetMethod(nameof(Dictionary.Add))!; + = typeof(Dictionary).GetMethod(nameof(Dictionary<,>.Add))!; [DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")] private sealed class NotTranslatedExpressionType : Expression, IPrintableExpression @@ -288,7 +285,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) private sealed class RuntimeParameterConstantLifter(ILiftableConstantFactory liftableConstantFactory) : ExpressionVisitor { private static readonly MethodInfo ComplexPropertyListElementAddMethod = - typeof(List).GetMethod(nameof(List.Add))!; + typeof(List).GetMethod(nameof(List<>.Add))!; protected override Expression VisitConstant(ConstantExpression constantExpression) { diff --git a/src/EFCore/Query/QueryParameterExpression.cs b/src/EFCore/Query/QueryParameterExpression.cs index dde4c03c09f..03f86fc1006 100644 --- a/src/EFCore/Query/QueryParameterExpression.cs +++ b/src/EFCore/Query/QueryParameterExpression.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Query.Internal; namespace Microsoft.EntityFrameworkCore.Query; diff --git a/src/EFCore/Query/QueryTranslationPreprocessor.cs b/src/EFCore/Query/QueryTranslationPreprocessor.cs index 7b3978c1795..85075dc2545 100644 --- a/src/EFCore/Query/QueryTranslationPreprocessor.cs +++ b/src/EFCore/Query/QueryTranslationPreprocessor.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Query.Internal; namespace Microsoft.EntityFrameworkCore.Query; diff --git a/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs index 58835b3dd34..0a5fd294b11 100644 --- a/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs @@ -187,7 +187,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp valueSelector = unwrappedValueSelector; } - setters[i] = new(propertySelector, valueSelector); + setters[i] = new ExecuteUpdateSetter(propertySelector, valueSelector); } return TranslateExecuteUpdate(shapedQueryExpression, setters) @@ -606,7 +606,7 @@ Expression CheckTranslated(ShapedQueryExpression? translated) // Identify property access, e.g. primitive collection property (context.Blogs.Where(b => b.Tags.Contains(...))) if (IsMemberAccess(methodCallExpression, QueryCompilationContext.Model, out var propertyAccessSource, out var propertyName) - && TranslateMemberAccess(propertyAccessSource, propertyName) is ShapedQueryExpression translation) + && TranslateMemberAccess(propertyAccessSource, propertyName) is { } translation) { return translation; } diff --git a/src/EFCore/Query/QueryableMethods.cs b/src/EFCore/Query/QueryableMethods.cs index 57a29d6a8df..08d1bc25821 100644 --- a/src/EFCore/Query/QueryableMethods.cs +++ b/src/EFCore/Query/QueryableMethods.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// @@ -390,7 +388,7 @@ public static class QueryableMethods //public static MethodInfo Zip { get; } /// - /// Checks whether or not the given is one of the without a selector. + /// Checks whether the given is one of the without a selector. /// /// The method to check. /// if the method matches; otherwise. @@ -398,7 +396,7 @@ public static bool IsAverageWithoutSelector(MethodInfo methodInfo) => AverageWithoutSelectorMethods.ContainsValue(methodInfo); /// - /// Checks whether or not the given is one of the with a selector. + /// Checks whether the given is one of the with a selector. /// /// The method to check. /// if the method matches; otherwise. @@ -407,7 +405,7 @@ public static bool IsAverageWithSelector(MethodInfo methodInfo) && AverageWithSelectorMethods.ContainsValue(methodInfo.GetGenericMethodDefinition()); /// - /// Checks whether or not the given is one of the without a selector. + /// Checks whether the given is one of the without a selector. /// /// The method to check. /// if the method matches; otherwise. @@ -415,7 +413,7 @@ public static bool IsSumWithoutSelector(MethodInfo methodInfo) => SumWithoutSelectorMethods.ContainsValue(methodInfo); /// - /// Checks whether or not the given is one of the with a selector. + /// Checks whether the given is one of the with a selector. /// /// The method to check. /// if the method matches; otherwise. @@ -460,7 +458,9 @@ public static MethodInfo GetSumWithSelector(Type type) private static Dictionary SumWithoutSelectorMethods { get; } private static Dictionary SumWithSelectorMethods { get; } - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Types used here in 'MakeGenericType' are types like 'TSource', not specific types.")] + [UnconditionalSuppressMessage( + "AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = "Types used here in 'MakeGenericType' are types like 'TSource', not specific types.")] static QueryableMethods() { var queryableMethodGroups = typeof(Queryable) @@ -883,10 +883,9 @@ static QueryableMethods() } MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) - => queryableMethodGroups[name].Single( - mi => ((genericParameterCount == 0 && !mi.IsGenericMethod) - || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) - && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( - parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : []))); + => queryableMethodGroups[name].Single(mi => ((genericParameterCount == 0 && !mi.IsGenericMethod) + || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) + && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( + parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : []))); } } diff --git a/src/EFCore/Query/ReplacingExpressionVisitor.cs b/src/EFCore/Query/ReplacingExpressionVisitor.cs index c78375f11fc..c81dcb05986 100644 --- a/src/EFCore/Query/ReplacingExpressionVisitor.cs +++ b/src/EFCore/Query/ReplacingExpressionVisitor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Query; /// @@ -31,7 +29,7 @@ public class ReplacingExpressionVisitor : ExpressionVisitor /// The expression tree in which replacement is going to be performed. /// An expression tree with replacements made. public static Expression Replace(Expression original, Expression replacement, Expression tree) - => new ReplacingExpressionVisitor(new[] { original }, new[] { replacement }).Visit(tree); + => new ReplacingExpressionVisitor([original], [replacement]).Visit(tree); /// /// Replaces one expression with another in given expression tree. @@ -83,7 +81,7 @@ protected override Expression VisitMember(MemberExpression memberExpression) var innerExpression = Visit(memberExpression.Expression); if (innerExpression is GroupByShaperExpression groupByShaperExpression - && memberExpression.Member.Name == nameof(IGrouping.Key)) + && memberExpression.Member.Name == nameof(IGrouping<,>.Key)) { return groupByShaperExpression.KeySelector; } @@ -99,8 +97,8 @@ protected override Expression VisitMember(MemberExpression memberExpression) var mayBeMemberInitExpression = innerExpression.UnwrapTypeConversion(out _); if (mayBeMemberInitExpression is MemberInitExpression memberInitExpression - && memberInitExpression.Bindings.SingleOrDefault( - mb => mb.Member.IsSameAs(memberExpression.Member)) is MemberAssignment memberAssignment) + && memberInitExpression.Bindings.SingleOrDefault(mb => mb.Member.IsSameAs(memberExpression.Member)) is MemberAssignment + memberAssignment) { return memberAssignment.Expression; } @@ -125,13 +123,12 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp var mayBeMemberInitExpression = newEntityExpression.UnwrapTypeConversion(out _); if (mayBeMemberInitExpression is MemberInitExpression memberInitExpression - && memberInitExpression.Bindings.SingleOrDefault( - mb => mb.Member.Name == propertyName) is MemberAssignment memberAssignment) + && memberInitExpression.Bindings.SingleOrDefault(mb => mb.Member.Name == propertyName) is MemberAssignment memberAssignment) { return memberAssignment.Expression; } - return methodCallExpression.Update(null, new[] { newEntityExpression, methodCallExpression.Arguments[1] }); + return methodCallExpression.Update(null, [newEntityExpression, methodCallExpression.Arguments[1]]); } return base.VisitMethodCall(methodCallExpression); diff --git a/src/EFCore/Query/SetPropertyCalls`.cs b/src/EFCore/Query/SetPropertyCalls`.cs index 67d4e8c01a0..712392302d0 100644 --- a/src/EFCore/Query/SetPropertyCalls`.cs +++ b/src/EFCore/Query/SetPropertyCalls`.cs @@ -25,7 +25,8 @@ public UpdateSettersBuilder() /// A value expression. /// /// The same instance so that multiple calls to - /// + /// /// can be chained. /// public UpdateSettersBuilder SetProperty( diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs index 3dba903bf1f..1fa5bffdcd3 100644 --- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs @@ -199,7 +199,7 @@ public static async Task SingleAsync( protected abstract Expression VisitShapedQuery(ShapedQueryExpression shapedQueryExpression); /// - /// This method has been obsoleted, see . + /// This method has been obsoleted, see . /// [Obsolete("Use InjectStructuralTypeMaterializers instead.", error: true)] protected virtual Expression InjectEntityMaterializers(Expression expression) @@ -279,8 +279,7 @@ protected virtual void VerifyNoClientConstant(Expression expression) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [UsedImplicitly] - [EntityFrameworkInternal] + [UsedImplicitly, EntityFrameworkInternal] public static Exception CreateNullKeyValueInNoTrackingQuery( IEntityType entityType, IReadOnlyList properties, @@ -423,7 +422,7 @@ public Expression Inject(Expression expression) { foreach (var entityType in _visitedEntityTypes) { - if (entityType.FindOwnership() is IForeignKey ownership + if (entityType.FindOwnership() is { } ownership && !ContainsOwner(ownership.PrincipalEntityType)) { throw new InvalidOperationException(CoreStrings.OwnedEntitiesCannotBeTrackedWithoutTheirOwner); @@ -507,11 +506,10 @@ private Expression ProcessStructuralTypeShaper(StructuralTypeShaperExpression sh NewArrayInit( typeof(object), primaryKey.Properties - .Select( - p => valueBufferExpression.CreateValueBufferReadValueExpression( - typeof(object), - p.GetIndex(), - p))), + .Select(p => valueBufferExpression.CreateValueBufferReadValueExpression( + typeof(object), + p.GetIndex(), + p))), Constant(!shaper.IsNullable), hasNullKeyVariable))); @@ -538,10 +536,9 @@ private Expression ProcessStructuralTypeShaper(StructuralTypeShaperExpression sh { expressions.Add( IfThen( - primaryKey.Properties.Select( - p => NotEqual( - valueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), - Constant(null))) + primaryKey.Properties.Select(p => NotEqual( + valueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), + Constant(null))) .Aggregate(AndAlso), MaterializeEntity( shaper, materializationContextVariable, concreteEntityTypeVariable, @@ -555,24 +552,22 @@ private Expression ProcessStructuralTypeShaper(StructuralTypeShaperExpression sh expressions.Add( IfThenElse( - primaryKey.Properties.Select( - p => NotEqual( - valueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), - Constant(null))) + primaryKey.Properties.Select(p => NotEqual( + valueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), + Constant(null))) .Aggregate(AndAlso), MaterializeEntity( shaper, materializationContextVariable, concreteEntityTypeVariable, instanceVariable, null), Block( - new[] { keyValuesVariable }, + [keyValuesVariable], Assign( keyValuesVariable, NewArrayInit( typeof(object), - primaryKey.Properties.Select( - p => valueBufferExpression.CreateValueBufferReadValueExpression( - typeof(object), p.GetIndex(), p)))), + primaryKey.Properties.Select(p => valueBufferExpression.CreateValueBufferReadValueExpression( + typeof(object), p.GetIndex(), p)))), Call( CreateNullKeyValueInNoTrackingQueryMethod, supportsPrecompiledQuery @@ -750,11 +745,10 @@ private BlockExpression CreateFullMaterializeExpression( runtimeEntityType, NewArrayInit( typeof(object), - shadowProperties.Select( - p => - Convert( - valueBufferExpression.CreateValueBufferReadValueExpression( - p.ClrType, p.GetIndex(), p), typeof(object))))))); + shadowProperties.Select(p => + Convert( + valueBufferExpression.CreateValueBufferReadValueExpression( + p.ClrType, p.GetIndex(), p), typeof(object))))))); } materializer = materializer.Type == returnType diff --git a/src/EFCore/Query/StructuralTypeShaperExpression.cs b/src/EFCore/Query/StructuralTypeShaperExpression.cs index 10c73ba14c0..03006addc9d 100644 --- a/src/EFCore/Query/StructuralTypeShaperExpression.cs +++ b/src/EFCore/Query/StructuralTypeShaperExpression.cs @@ -32,8 +32,7 @@ private static readonly MethodInfo GetDiscriminatorValueMethod /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [UsedImplicitly] - [EntityFrameworkInternal] + [UsedImplicitly, EntityFrameworkInternal] public static Exception CreateUnableToDiscriminateException(ITypeBase type, object? discriminator) => new InvalidOperationException(CoreStrings.UnableToDiscriminate(type.DisplayName(), discriminator?.ToString())); @@ -190,10 +189,9 @@ protected virtual LambdaExpression GenerateMaterializationCondition(ITypeBase ty // null, return null for the entity instance. body = Condition( entityType.GetProperties() - .Select( - p => NotEqual( - valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), - Constant(null))) + .Select(p => NotEqual( + valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), + Constant(null))) .Aggregate(OrElse), body, Default(typeof(IEntityType))); diff --git a/src/EFCore/Query/TransparentIdentifierFactory.cs b/src/EFCore/Query/TransparentIdentifierFactory.cs index 15c0417906d..9c880ca4eba 100644 --- a/src/EFCore/Query/TransparentIdentifierFactory.cs +++ b/src/EFCore/Query/TransparentIdentifierFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; namespace Microsoft.EntityFrameworkCore.Query; diff --git a/src/EFCore/Query/UpdateSettersBuilder.cs b/src/EFCore/Query/UpdateSettersBuilder.cs index 9e25147f8ce..0cf02a38a79 100644 --- a/src/EFCore/Query/UpdateSettersBuilder.cs +++ b/src/EFCore/Query/UpdateSettersBuilder.cs @@ -21,7 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Query; /// public class UpdateSettersBuilder { - private readonly List _setters = new(); + private readonly List _setters = []; private static ConstructorInfo? _setterTupleConstructor; diff --git a/src/EFCore/Storage/CoreTypeMapping.cs b/src/EFCore/Storage/CoreTypeMapping.cs index dbbaf41c730..95063a379fc 100644 --- a/src/EFCore/Storage/CoreTypeMapping.cs +++ b/src/EFCore/Storage/CoreTypeMapping.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Storage.Internal; diff --git a/src/EFCore/Storage/Database.cs b/src/EFCore/Storage/Database.cs index ebdcd0b891a..a92b530836c 100644 --- a/src/EFCore/Storage/Database.cs +++ b/src/EFCore/Storage/Database.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Storage; /// diff --git a/src/EFCore/Storage/ExecutionStrategy.cs b/src/EFCore/Storage/ExecutionStrategy.cs index 75d8df5efd2..f8a1bd0ce0e 100644 --- a/src/EFCore/Storage/ExecutionStrategy.cs +++ b/src/EFCore/Storage/ExecutionStrategy.cs @@ -201,7 +201,7 @@ public virtual TResult Execute( // In order to avoid infinite recursive generics, wrap operation with ExecutionResult return ExecuteImplementation( - (context, state) => new ExecutionResult(true, operation(context, state)), + (context, innerState) => new ExecutionResult(true, operation(context, innerState)), verifySucceeded, state).Result; } @@ -304,8 +304,8 @@ public virtual async Task ExecuteAsync( // In order to avoid infinite recursive generics, wrap operation with ExecutionResult var result = await ExecuteImplementationAsync( - async (context, state, cancellationToken) => new ExecutionResult( - true, await operation(context, state, cancellationToken).ConfigureAwait(false)), + async (context, innerState, cancellationToken) => new ExecutionResult( + true, await operation(context, innerState, cancellationToken).ConfigureAwait(false)), verifySucceeded, state, cancellationToken).ConfigureAwait(false); @@ -489,7 +489,7 @@ public static TResult CallOnWrappedException( { while (true) { - if (exception is DbUpdateException { InnerException: Exception innerException }) + if (exception is DbUpdateException { InnerException: { } innerException }) { exception = innerException; continue; diff --git a/src/EFCore/Storage/IDatabase.cs b/src/EFCore/Storage/IDatabase.cs index 69ee1952b1d..ccbb032e36a 100644 --- a/src/EFCore/Storage/IDatabase.cs +++ b/src/EFCore/Storage/IDatabase.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.Storage; /// diff --git a/src/EFCore/Storage/IDatabaseCreator.cs b/src/EFCore/Storage/IDatabaseCreator.cs index bf52b463fb6..6fdaa644d8f 100644 --- a/src/EFCore/Storage/IDatabaseCreator.cs +++ b/src/EFCore/Storage/IDatabaseCreator.cs @@ -79,7 +79,7 @@ public interface IDatabaseCreator Task EnsureCreatedAsync(CancellationToken cancellationToken = default); /// - /// Determines whether or not the database is available and can be connected to. + /// Determines whether the database is available and can be connected to. /// /// /// Note that being able to connect to the database does not mean that it is @@ -89,7 +89,7 @@ public interface IDatabaseCreator bool CanConnect(); /// - /// Determines whether or not the database is available and can be connected to. + /// Determines whether the database is available and can be connected to. /// /// /// Note that being able to connect to the database does not mean that it is diff --git a/src/EFCore/Storage/Json/JsonValueReaderWriter.cs b/src/EFCore/Storage/Json/JsonValueReaderWriter.cs index 4e07ab8325b..24600a0a93c 100644 --- a/src/EFCore/Storage/Json/JsonValueReaderWriter.cs +++ b/src/EFCore/Storage/Json/JsonValueReaderWriter.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.Json; diff --git a/src/EFCore/Storage/TypeMappingInfo.cs b/src/EFCore/Storage/TypeMappingInfo.cs index 7ab3656b8ec..a9bb8644ea8 100644 --- a/src/EFCore/Storage/TypeMappingInfo.cs +++ b/src/EFCore/Storage/TypeMappingInfo.cs @@ -320,12 +320,12 @@ public TypeMappingInfo WithConverter(in ValueConverterInfo converterInfo) => new(this, converterInfo); /// - /// Indicates whether or not the mapping is part of a key or foreign key. + /// Indicates whether the mapping is part of a key or foreign key. /// public bool IsKey { get; init; } /// - /// Indicates whether or not the mapping is part of a key, foreign key, or index. + /// Indicates whether the mapping is part of a key, foreign key, or index. /// public bool IsKeyOrIndex { get; init; } @@ -335,12 +335,12 @@ public TypeMappingInfo WithConverter(in ValueConverterInfo converterInfo) public int? Size { get; init; } /// - /// Indicates whether or not the mapping supports Unicode, or if not defined. + /// Indicates whether the mapping supports Unicode, or if not defined. /// public bool? IsUnicode { get; init; } /// - /// Indicates whether or not the mapping will be used for a row version, or if not defined. + /// Indicates whether the mapping will be used for a row version, or if not defined. /// public bool? IsRowVersion { get; init; } diff --git a/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs b/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs index 829ddbda7a0..ab019c03911 100644 --- a/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs +++ b/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs @@ -21,7 +21,7 @@ public class ConverterMappingHints /// The suggested size of the mapped data type. /// The suggested precision of the mapped data type. /// The suggested scale of the mapped data type. - /// Whether or not the mapped data type should support Unicode. + /// Whether the mapped data type should support Unicode. /// An optional factory for creating a specific . public ConverterMappingHints( int? size = null, @@ -50,7 +50,7 @@ public ConverterMappingHints( public virtual ConverterMappingHints With(ConverterMappingHints? hints) => hints == null ? this - : hints.GetType().IsAssignableFrom(GetType()) + : hints.GetType().IsInstanceOfType(this) ? new ConverterMappingHints( hints.Size ?? Size, hints.Precision ?? Precision, @@ -72,7 +72,7 @@ public virtual ConverterMappingHints With(ConverterMappingHints? hints) public virtual ConverterMappingHints OverrideWith(ConverterMappingHints? hints) => hints == null ? this - : GetType().IsAssignableFrom(hints.GetType()) + : GetType().IsInstanceOfType(hints) ? new ConverterMappingHints( Size ?? hints.Size, Precision ?? hints.Precision, @@ -99,7 +99,7 @@ public virtual ConverterMappingHints OverrideWith(ConverterMappingHints? hints) public virtual int? Scale { get; } /// - /// Whether or not the mapped data type should support Unicode. + /// Whether the mapped data type should support Unicode. /// public virtual bool? IsUnicode { get; } diff --git a/src/EFCore/Storage/ValueConversion/NumberToBytesConverter.cs b/src/EFCore/Storage/ValueConversion/NumberToBytesConverter.cs index 39986795e88..bd8a13441c0 100644 --- a/src/EFCore/Storage/ValueConversion/NumberToBytesConverter.cs +++ b/src/EFCore/Storage/ValueConversion/NumberToBytesConverter.cs @@ -108,7 +108,7 @@ public static Expression> ToBytes() output = Expression.Condition( Expression.Property( param, - typeof(TNumber).GetProperty(nameof(Nullable.HasValue))!), + typeof(TNumber).GetProperty(nameof(Nullable<>.HasValue))!), output, Expression.Constant(null, typeof(byte[]))); } diff --git a/src/EFCore/Storage/ValueConversion/ValueConverter.cs b/src/EFCore/Storage/ValueConversion/ValueConverter.cs index 2f82e106f51..60abf460f82 100644 --- a/src/EFCore/Storage/ValueConversion/ValueConverter.cs +++ b/src/EFCore/Storage/ValueConversion/ValueConverter.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; @@ -16,6 +15,10 @@ namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion; /// public abstract class ValueConverter { + internal static readonly ConstructorInfo MappingHintsCtor + = typeof(ConverterMappingHints).GetConstructor( + [typeof(int?), typeof(int?), typeof(int?), typeof(bool?), typeof(Func)])!; + /// /// Initializes a new instance of the class. /// diff --git a/src/EFCore/Storage/ValueConversion/ValueConverterSelector.cs b/src/EFCore/Storage/ValueConversion/ValueConverterSelector.cs index 7c38b53975b..8501e8005af 100644 --- a/src/EFCore/Storage/ValueConversion/ValueConverterSelector.cs +++ b/src/EFCore/Storage/ValueConversion/ValueConverterSelector.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.NetworkInformation; diff --git a/src/EFCore/Storage/ValueConversion/ValueConverter`.cs b/src/EFCore/Storage/ValueConversion/ValueConverter`.cs index c70fb9d6061..55493d83522 100644 --- a/src/EFCore/Storage/ValueConversion/ValueConverter`.cs +++ b/src/EFCore/Storage/ValueConversion/ValueConverter`.cs @@ -14,15 +14,6 @@ namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion; /// public class ValueConverter : ValueConverter { - private Func? _convertToProvider; - private Func? _convertFromProvider; - private Func? _convertToProviderTyped; - private Func? _convertFromProviderTyped; - - private static readonly ConstructorInfo MappingHintsCtor - = typeof(ConverterMappingHints).GetConstructor( - [typeof(int?), typeof(int?), typeof(int?), typeof(bool?), typeof(Func)])!; - /// /// Initializes a new instance of the class. /// @@ -102,9 +93,10 @@ private static T Sanitize(object value) /// /// See EF Core value converters for more information and examples. /// + [field: AllowNull, MaybeNull] public override Func ConvertToProvider => NonCapturingLazyInitializer.EnsureInitialized( - ref _convertToProvider, this, static c => SanitizeConverter(c.ConvertToProviderTyped, c.ConvertsNulls)); + ref field, this, static c => SanitizeConverter(c.ConvertToProviderTyped, c.ConvertsNulls)); /// /// Gets the function to convert objects when reading data from the store, @@ -113,9 +105,10 @@ private static T Sanitize(object value) /// /// See EF Core value converters for more information and examples. /// + [field: AllowNull, MaybeNull] public override Func ConvertFromProvider => NonCapturingLazyInitializer.EnsureInitialized( - ref _convertFromProvider, this, static c => SanitizeConverter(c.ConvertFromProviderTyped, c.ConvertsNulls)); + ref field, this, static c => SanitizeConverter(c.ConvertFromProviderTyped, c.ConvertsNulls)); /// /// Gets the function to convert objects when writing data to the store. @@ -123,9 +116,10 @@ private static T Sanitize(object value) /// /// See EF Core value converters for more information and examples. /// + [field: AllowNull, MaybeNull] public virtual Func ConvertToProviderTyped => NonCapturingLazyInitializer.EnsureInitialized( - ref _convertToProviderTyped, this, static c => c.ConvertToProviderExpression.Compile()); + ref field, this, static c => c.ConvertToProviderExpression.Compile()); /// /// Gets the function to convert objects when reading data from the store. @@ -133,9 +127,10 @@ public virtual Func ConvertToProviderTyped /// /// See EF Core value converters for more information and examples. /// + [field: AllowNull, MaybeNull] public virtual Func ConvertFromProviderTyped => NonCapturingLazyInitializer.EnsureInitialized( - ref _convertFromProviderTyped, this, static c => c.ConvertFromProviderExpression.Compile()); + ref field, this, static c => c.ConvertFromProviderExpression.Compile()); /// /// Gets the expression to convert objects when writing data to the store, diff --git a/src/EFCore/Update/UpdateEntryExtensions.cs b/src/EFCore/Update/UpdateEntryExtensions.cs index c8b3db84874..fc8e07fbe25 100644 --- a/src/EFCore/Update/UpdateEntryExtensions.cs +++ b/src/EFCore/Update/UpdateEntryExtensions.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Globalization; using System.Text; -using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -313,16 +312,15 @@ public static string BuildCurrentValuesString( IEnumerable properties) => "{" + string.Join( - ", ", properties.Select( - p => - { - var currentValue = entry.GetCurrentValue(p); - return p.Name - + ": " - + (currentValue == null - ? "" - : Convert.ToString(currentValue, CultureInfo.InvariantCulture)); - })) + ", ", properties.Select(p => + { + var currentValue = entry.GetCurrentValue(p); + return p.Name + + ": " + + (currentValue == null + ? "" + : Convert.ToString(currentValue, CultureInfo.InvariantCulture)); + })) + "}"; /// @@ -338,15 +336,14 @@ public static string BuildOriginalValuesString( IEnumerable properties) => "{" + string.Join( - ", ", properties.Select( - p => - { - var originalValue = entry.GetOriginalValue(p); - return p.Name - + ": " - + (originalValue == null - ? "" - : Convert.ToString(originalValue, CultureInfo.InvariantCulture)); - })) + ", ", properties.Select(p => + { + var originalValue = entry.GetOriginalValue(p); + return p.Name + + ": " + + (originalValue == null + ? "" + : Convert.ToString(originalValue, CultureInfo.InvariantCulture)); + })) + "}"; } diff --git a/src/EFCore/ValueGeneration/ValueGeneratorFactory.cs b/src/EFCore/ValueGeneration/ValueGeneratorFactory.cs index aff8ad1cfba..fef6319e83e 100644 --- a/src/EFCore/ValueGeneration/ValueGeneratorFactory.cs +++ b/src/EFCore/ValueGeneration/ValueGeneratorFactory.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.EntityFrameworkCore.ValueGeneration; /// diff --git a/src/EFCore/buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props b/src/EFCore/buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props index 9a8580ae56b..2d4c86c9b74 100644 --- a/src/EFCore/buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props +++ b/src/EFCore/buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props @@ -6,4 +6,4 @@ --> true - + \ No newline at end of file diff --git a/src/Shared/BidirectionalDictionary.cs b/src/Shared/BidirectionalDictionary.cs index 878347a714e..146fcfc9c57 100644 --- a/src/Shared/BidirectionalDictionary.cs +++ b/src/Shared/BidirectionalDictionary.cs @@ -6,355 +6,419 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; -namespace Microsoft.EntityFrameworkCore.Utilities +namespace Microsoft.EntityFrameworkCore.Utilities; + +/// +/// Represents a dictionary with non-null unique values that contains an inverse dictionary. +/// +/// The type of the keys in the dictionary. +/// The type of the values in the dictionary. +[DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] +[DebuggerDisplay("Count = {Count}")] +internal sealed class BidirectionalDictionary : IDictionary, IReadOnlyDictionary + where TKey : notnull + where TValue : notnull { + private readonly Dictionary _dictionary; + /// - /// Represents a dictionary with non-null unique values that contains an inverse dictionary. + /// Initializes a new instance of the class that is empty, + /// has the default initial capacity, and uses the default equality comparers. /// - /// The type of the keys in the dictionary. - /// The type of the values in the dictionary. - [DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] - [DebuggerDisplay("Count = {Count}")] - internal sealed class BidirectionalDictionary : IDictionary, IReadOnlyDictionary - where TKey : notnull - where TValue : notnull + public BidirectionalDictionary() + : this(new Dictionary()) { - private readonly Dictionary _dictionary; + } - /// - /// Initializes a new instance of the class that is empty, - /// has the default initial capacity, and uses the default equality comparers. - /// - public BidirectionalDictionary() : this(new Dictionary()) - { - } + /// + /// Initializes a new instance of the class that is empty, + /// has the specified initial capacity, and uses the default equality comparers. + /// + /// The initial number of elements that can contain. + public BidirectionalDictionary(int capacity) + : this(capacity, null, null) + { + } - /// - /// Initializes a new instance of the class that is empty, - /// has the specified initial capacity, and uses the default equality comparers. - /// - /// The initial number of elements that can contain. - public BidirectionalDictionary(int capacity) : this(capacity, null, null) - { - } + /// + /// Initializes a new instance of the class + /// that contains elements copied from the specified + /// and uses the default equality comparers. + /// + /// + /// The whose elements are copied to the new + /// . + /// + public BidirectionalDictionary(IDictionary dictionary) + : this(new Dictionary(dictionary)) + { + } - /// - /// Initializes a new instance of the class - /// that contains elements copied from the specified - /// and uses the default equality comparers. - /// - /// The whose elements are copied to the new . - public BidirectionalDictionary(IDictionary dictionary) - : this(new Dictionary(dictionary)) - { - } + /// + /// Initializes a new instance of the class + /// that contains elements copied from the specified + /// and uses the default equality comparers. + /// + /// + /// The whose elements are copied to the new + /// . + /// + public BidirectionalDictionary(IEnumerable> collection) + : this(new Dictionary(collection)) + { + } - /// - /// Initializes a new instance of the class - /// that contains elements copied from the specified - /// and uses the default equality comparers. - /// - /// The whose elements are copied to the new . - public BidirectionalDictionary(IEnumerable> collection) - : this(new Dictionary(collection)) - { - } + /// + /// Initializes a new instance of the class that is empty, + /// has the default initial capacity, and uses the specified equality comparers. + /// + /// + /// The implementation to use when + /// comparing keys, or null to use the default for the type of the key. + /// + /// + /// The implementation to use when + /// comparing values, or null to use the default for the type of the value. + /// + public BidirectionalDictionary(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) + : this(new Dictionary(keyComparer), valueComparer) + { + } - /// - /// Initializes a new instance of the class that is empty, - /// has the default initial capacity, and uses the specified equality comparers. - /// - /// The implementation to use when - /// comparing keys, or null to use the default for the type of the key. - /// The implementation to use when - /// comparing values, or null to use the default for the type of the value. - public BidirectionalDictionary(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) - : this(new Dictionary(keyComparer), valueComparer) - { - } + /// + /// Initializes a new instance of the class that is empty, + /// has the specified initial capacity, and uses the specified equality comparers. + /// + /// The initial number of elements that can contain. + /// + /// The implementation to use when + /// comparing keys, or null to use the default for the type of the key. + /// + /// + /// The implementation to use when + /// comparing values, or null to use the default for the type of the value. + /// + public BidirectionalDictionary(int capacity, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) + : this(new Dictionary(capacity, keyComparer), valueComparer) + { + } - /// - /// Initializes a new instance of the class that is empty, - /// has the specified initial capacity, and uses the specified equality comparers. - /// - /// The initial number of elements that can contain. - /// The implementation to use when - /// comparing keys, or null to use the default for the type of the key. - /// The implementation to use when - /// comparing values, or null to use the default for the type of the value. - public BidirectionalDictionary(int capacity, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) - : this(new Dictionary(capacity, keyComparer), valueComparer) - { - } + /// + /// Initializes a new instance of the class that + /// contains elements copied from the specified , and uses the specified equality comparers. + /// + /// + /// The whose elements are copied to the new + /// . + /// + /// + /// The implementation to use when + /// comparing keys, or null to use the default for the type of the key. + /// + /// + /// The implementation to use when + /// comparing values, or null to use the default for the type of the value. + /// + public BidirectionalDictionary( + IDictionary dictionary, + IEqualityComparer? keyComparer, + IEqualityComparer? valueComparer) + : this(new Dictionary(dictionary, keyComparer), valueComparer) + { + } - /// - /// Initializes a new instance of the class that - /// contains elements copied from the specified , and uses the specified equality comparers. - /// - /// The whose elements are copied to the new . - /// The implementation to use when - /// comparing keys, or null to use the default for the type of the key. - /// The implementation to use when - /// comparing values, or null to use the default for the type of the value. - public BidirectionalDictionary( - IDictionary dictionary, - IEqualityComparer? keyComparer, - IEqualityComparer? valueComparer) - : this(new Dictionary(dictionary, keyComparer), valueComparer) - { - } + /// + /// Initializes a new instance of the class that + /// contains elements copied from the specified , and uses the specified equality comparers. + /// + /// + /// The whose elements are copied to the new + /// . + /// + /// + /// The implementation to use when + /// comparing keys, or null to use the default for the type of the key. + /// + /// + /// The implementation to use when + /// comparing values, or null to use the default for the type of the value. + /// + public BidirectionalDictionary( + IEnumerable> collection, + IEqualityComparer? keyComparer, + IEqualityComparer? valueComparer) + : this(new Dictionary(collection, keyComparer), valueComparer) + { + } - /// - /// Initializes a new instance of the class that - /// contains elements copied from the specified , and uses the specified equality comparers. - /// - /// The whose elements are copied to the new . - /// The implementation to use when - /// comparing keys, or null to use the default for the type of the key. - /// The implementation to use when - /// comparing values, or null to use the default for the type of the value. - public BidirectionalDictionary( - IEnumerable> collection, - IEqualityComparer? keyComparer, - IEqualityComparer? valueComparer) - : this(new Dictionary(collection, keyComparer), valueComparer) - { - } + private BidirectionalDictionary(BidirectionalDictionary inverse, IEqualityComparer? keyComparer = null) + { + _dictionary = inverse._dictionary.ToDictionary(pair => pair.Value, pair => pair.Key, keyComparer); + Inverse = inverse; + } - private BidirectionalDictionary(BidirectionalDictionary inverse, IEqualityComparer? keyComparer = null) - { - _dictionary = inverse._dictionary.ToDictionary(pair => pair.Value, pair => pair.Key, keyComparer); - Inverse = inverse; - } + private BidirectionalDictionary(Dictionary dictionary, IEqualityComparer? valueComparer = null) + { + _dictionary = dictionary; + Inverse = new BidirectionalDictionary(this, valueComparer ?? EqualityComparer.Default); + } - private BidirectionalDictionary(Dictionary dictionary, IEqualityComparer? valueComparer = null) - { - _dictionary = dictionary; - Inverse = new BidirectionalDictionary(this, valueComparer ?? EqualityComparer.Default); - } + /// + /// Gets the inverse . + /// + public BidirectionalDictionary Inverse { get; } + + /// + /// Gets the number of key/value pairs contained in the . + /// + public int Count + => _dictionary.Count; + + /// + /// Gets a collection containing the keys in the . + /// + public Dictionary.KeyCollection Keys + => _dictionary.Keys; + + /// + /// Gets a collection containing the values in the . + /// + public Dictionary.ValueCollection Values + => _dictionary.Values; + + /// + /// Gets the that is used to determine equality of keys for the dictionary. + /// + public IEqualityComparer KeyValueComparer + => _dictionary.Comparer; + + /// + /// Gets the that is used to determine equality of values for the dictionary. + /// + public IEqualityComparer ValueComparer + => Inverse._dictionary.Comparer; - /// - /// Gets the inverse . - /// - public BidirectionalDictionary Inverse { get; } - - /// - /// Gets the number of key/value pairs contained in the . - /// - public int Count => _dictionary.Count; - - /// - /// Gets a collection containing the keys in the . - /// - public Dictionary.KeyCollection Keys => _dictionary.Keys; - - /// - /// Gets a collection containing the values in the . - /// - public Dictionary.ValueCollection Values => _dictionary.Values; - - /// - /// Gets the that is used to determine equality of keys for the dictionary. - /// - public IEqualityComparer KeyValueComparer => _dictionary.Comparer; - - /// - /// Gets the that is used to determine equality of values for the dictionary. - /// - public IEqualityComparer ValueComparer => Inverse._dictionary.Comparer; - - /// - /// Gets or sets the value associated with the specified key. - /// - /// The key of the value to get or set. - /// The value associated with the specified key. If the specified key is not found, a get operation throws a - /// , and a set operation creates a new element with the specified key. - public TValue this[TKey key] + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key of the value to get or set. + /// + /// The value associated with the specified key. If the specified key is not found, a get operation throws a + /// , and a set operation creates a new element with the specified key. + /// + public TValue this[TKey key] + { + get => _dictionary[key]; + set { - get => _dictionary[key]; - set - { - Check.NotNull(value); + Check.NotNull(value); - if (TryGetValue(key, out var oldValue)) - { - if (ValueComparer.Equals(oldValue, value)) - { - return; - } - - Inverse._dictionary.Add(value, key); - Inverse._dictionary.Remove(oldValue); - _dictionary[key] = value; - } - else + if (TryGetValue(key, out var oldValue)) + { + if (ValueComparer.Equals(oldValue, value)) { - Add(key, value); + return; } - } - } - /// - /// Adds the specified key and value to the dictionary. - /// - /// The key of the element to add. - /// The value of the element to add. - public void Add(TKey key, TValue value) - { - if (ContainsKey(key)) + Inverse._dictionary.Add(value, key); + Inverse._dictionary.Remove(oldValue); + _dictionary[key] = value; + } + else { - _dictionary.Add(key, value); + Add(key, value); } + } + } - Inverse._dictionary.Add(value, key); + /// + /// Adds the specified key and value to the dictionary. + /// + /// The key of the element to add. + /// The value of the element to add. + public void Add(TKey key, TValue value) + { + if (ContainsKey(key)) + { _dictionary.Add(key, value); } - /// - /// Removes the value with the specified key from the . - /// - /// The key of the element to remove. - /// if the element is successfully found and removed; otherwise, . - /// This method returns if key is not found in the . - public bool Remove(TKey key) => Remove(key, out _); - - /// - /// Removes the value with the specified key from the . - /// - /// The key of the element to remove. - /// When this method returns, contains the value associated with the specified key, - /// if the key is found; otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// if the element is successfully found and removed; otherwise, . - /// This method returns if key is not found in the . - public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) - => _dictionary.Remove(key, out value) + Inverse._dictionary.Add(value, key); + _dictionary.Add(key, value); + } + + /// + /// Removes the value with the specified key from the . + /// + /// The key of the element to remove. + /// + /// if the element is successfully found and removed; otherwise, . + /// This method returns if key is not found in the . + /// + public bool Remove(TKey key) + => Remove(key, out _); + + /// + /// Removes the value with the specified key from the . + /// + /// The key of the element to remove. + /// + /// When this method returns, contains the value associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// + /// if the element is successfully found and removed; otherwise, . + /// This method returns if key is not found in the . + /// + public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) + => _dictionary.Remove(key, out value) && Inverse._dictionary.Remove(value); - /// - /// Removes all keys and values from the . - /// - public void Clear() + /// + /// Removes all keys and values from the . + /// + public void Clear() + { + _dictionary.Clear(); + Inverse._dictionary.Clear(); + } + + /// + /// Determines whether the contains the specified key. + /// + /// The key to locate in the . + /// + /// if the contains + /// an element with the specified key; otherwise, . + /// + public bool ContainsKey(TKey key) + => _dictionary.ContainsKey(key); + + /// + /// Determines whether the contains the specified value. + /// + /// The value to locate in the . + /// + /// if the contains + /// an element with the specified value; otherwise, . + /// + public bool ContainsValue(TValue value) + => Inverse._dictionary.ContainsKey(value); + + /// + /// Attempts to add the specified key and value to the . + /// + /// The key of the element to add. + /// The value of the element to add. + /// + /// if the key/value pair was added to the + /// successfully; otherwise, . + /// + public bool TryAdd(TKey key, TValue value) + { + if (ContainsKey(key) || ContainsValue(value)) { - _dictionary.Clear(); - Inverse._dictionary.Clear(); + return false; } - /// - /// Determines whether the contains the specified key. - /// - /// The key to locate in the . - /// if the contains - /// an element with the specified key; otherwise, . - public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key); - - /// - /// Determines whether the contains the specified value. - /// - /// The value to locate in the . - /// if the contains - /// an element with the specified value; otherwise, . - public bool ContainsValue(TValue value) => Inverse._dictionary.ContainsKey(value); - - /// - /// Attempts to add the specified key and value to the . - /// - /// The key of the element to add. - /// The value of the element to add. - /// if the key/value pair was added to the - /// successfully; otherwise, . - public bool TryAdd(TKey key, TValue value) - { - if (ContainsKey(key) || ContainsValue(value)) - { - return false; - } + _dictionary.Add(key, value); + Inverse._dictionary.Add(value, key); - _dictionary.Add(key, value); - Inverse._dictionary.Add(value, key); + return true; + } - return true; - } + /// + /// Gets the value associated with the specified key. + /// + /// The key of the value to get. + /// + /// When this method returns, contains the value associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// + /// if the contains + /// an element with the specified key; otherwise, . + /// + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + => _dictionary.TryGetValue(key, out value); - /// - /// Gets the value associated with the specified key. - /// - /// The key of the value to get. - /// When this method returns, contains the value associated with the specified key, - /// if the key is found; otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// if the contains - /// an element with the specified key; otherwise, . - public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => _dictionary.TryGetValue(key, out value); - - /// - /// Resizes the internal data structure if necessary to ensure no additional resizing to support the specified capacity. - /// - /// The number of elements that the must be able to contain. - /// The capacity of the . - public int EnsureCapacity(int capacity) - { - _dictionary.EnsureCapacity(capacity); - return Inverse._dictionary.EnsureCapacity(capacity); - } + /// + /// Resizes the internal data structure if necessary to ensure no additional resizing to support the specified capacity. + /// + /// The number of elements that the must be able to contain. + /// The capacity of the . + public int EnsureCapacity(int capacity) + { + _dictionary.EnsureCapacity(capacity); + return Inverse._dictionary.EnsureCapacity(capacity); + } - /// - /// Sets the capacity of an object to the actual number of elements it contains, - /// rounded up to a nearby, implementation-specific value. - /// - public void TrimExcess() - { - _dictionary.TrimExcess(); - Inverse._dictionary.TrimExcess(); - } + /// + /// Sets the capacity of an object to the actual number of elements it contains, + /// rounded up to a nearby, implementation-specific value. + /// + public void TrimExcess() + { + _dictionary.TrimExcess(); + Inverse._dictionary.TrimExcess(); + } - /// - /// Sets the capacity of an object to the specified capacity, rounded up to a nearby, - /// implementation-specific value. - /// - /// The number of elements that the must be able to contain. - public void TrimExcess(int capacity) - { - _dictionary.TrimExcess(capacity); - Inverse._dictionary.TrimExcess(capacity); - } + /// + /// Sets the capacity of an object to the specified capacity, rounded up to a nearby, + /// implementation-specific value. + /// + /// The number of elements that the must be able to contain. + public void TrimExcess(int capacity) + { + _dictionary.TrimExcess(capacity); + Inverse._dictionary.TrimExcess(capacity); + } - /// - /// Returns an wrapper for the current dictionary. - /// - /// An object that acts as a read-only wrapper around the current . - public IReadOnlyDictionary AsReadOnly() => _dictionary; + /// + /// Returns an wrapper for the current dictionary. + /// + /// An object that acts as a read-only wrapper around the current . + public IReadOnlyDictionary AsReadOnly() + => _dictionary; - public IEnumerator GetEnumerator() => _dictionary.GetEnumerator(); + public IEnumerator GetEnumerator() + => _dictionary.GetEnumerator(); - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - ICollection IDictionary.Keys => Keys; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + ICollection IDictionary.Keys + => Keys; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - ICollection IDictionary.Values => Values; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + ICollection IDictionary.Values + => Values; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - IEnumerable IReadOnlyDictionary.Keys => Keys; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + IEnumerable IReadOnlyDictionary.Keys + => Keys; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - IEnumerable IReadOnlyDictionary.Values => Values; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + IEnumerable IReadOnlyDictionary.Values + => Values; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - bool ICollection>.IsReadOnly => false; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + bool ICollection>.IsReadOnly + => false; - void ICollection>.Add(KeyValuePair item) => Add(item.Key, item.Value); + void ICollection>.Add(KeyValuePair item) + => Add(item.Key, item.Value); - bool ICollection>.Remove(KeyValuePair item) - => ((ICollection>)_dictionary).Remove(item) + bool ICollection>.Remove(KeyValuePair item) + => ((ICollection>)_dictionary).Remove(item) && Inverse._dictionary.Remove(item.Value); - bool ICollection>.Contains(KeyValuePair item) - => ((ICollection>)_dictionary).Contains(item); + bool ICollection>.Contains(KeyValuePair item) + => ((ICollection>)_dictionary).Contains(item); - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - => ((ICollection>)_dictionary).CopyTo(array, arrayIndex); + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + => ((ICollection>)_dictionary).CopyTo(array, arrayIndex); - IEnumerator> IEnumerable>.GetEnumerator() - => _dictionary.GetEnumerator(); - } + IEnumerator> IEnumerable>.GetEnumerator() + => _dictionary.GetEnumerator(); } diff --git a/src/Shared/Check.cs b/src/Shared/Check.cs index 331f233146d..ef4aec9b66c 100644 --- a/src/Shared/Check.cs +++ b/src/Shared/Check.cs @@ -56,7 +56,6 @@ public static string NotEmpty( return value; } - public static string? NullButNotEmpty( string? value, [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") @@ -76,6 +75,7 @@ public static IReadOnlyList HasNoNulls( { NotNull(value, parameterName); + // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < value.Count; i++) { if (value[i] is null) @@ -105,7 +105,9 @@ public static IReadOnlyList HasNoEmptyElements( } [Conditional("DEBUG")] - public static void DebugAssert([DoesNotReturnIf(false)] bool condition, [CallerArgumentExpression(nameof(condition))] string message = "") + public static void DebugAssert( + [DoesNotReturnIf(false)] bool condition, + [CallerArgumentExpression(nameof(condition))] string message = "") { if (!condition) { @@ -113,8 +115,7 @@ public static void DebugAssert([DoesNotReturnIf(false)] bool condition, [CallerA } } - [Conditional("DEBUG")] - [DoesNotReturn] + [Conditional("DEBUG"), DoesNotReturn] public static void DebugFail(string message) => throw new UnreachableException($"Check.DebugFail failed: {message}"); diff --git a/src/Shared/DisposableExtensions.cs b/src/Shared/DisposableExtensions.cs index e43c01870ec..e4bd0f0c173 100644 --- a/src/Shared/DisposableExtensions.cs +++ b/src/Shared/DisposableExtensions.cs @@ -9,16 +9,15 @@ internal static class DisposableExtensions { public static ValueTask DisposeAsyncIfAvailable(this IDisposable? disposable) { - if (disposable != null) + switch (disposable) { - if (disposable is IAsyncDisposable asyncDisposable) - { + case null: + return default; + case IAsyncDisposable asyncDisposable: return asyncDisposable.DisposeAsync(); - } - - disposable.Dispose(); + default: + disposable.Dispose(); + return default; } - - return default; } } diff --git a/src/Shared/EnumerableExtensions.cs b/src/Shared/EnumerableExtensions.cs index bcf7b63e0a0..13e410b3b88 100644 --- a/src/Shared/EnumerableExtensions.cs +++ b/src/Shared/EnumerableExtensions.cs @@ -104,9 +104,8 @@ public static int IndexOf( this IEnumerable source, T item, IEqualityComparer comparer) - => source.Select( - (x, index) => - comparer.Equals(item, x) ? index : -1) + => source.Select((x, index) => + comparer.Equals(item, x) ? index : -1) .FirstOr(x => x != -1, -1); public static T FirstOr(this IEnumerable source, T alternate) @@ -128,11 +127,12 @@ public static bool Any(this IEnumerable source) public static List ToList(this IEnumerable source) => [.. source.OfType()]; - public static IList AsList(this IEnumerable source) => source switch - { - IList list => list, - _ => [.. source] - }; + public static IList AsList(this IEnumerable source) + => source switch + { + IList list => list, + _ => [.. source] + }; public static string Format(this IEnumerable strings) => "{" diff --git a/src/Shared/EnumerableMethods.cs b/src/Shared/EnumerableMethods.cs index d182175f76f..020d1008651 100644 --- a/src/Shared/EnumerableMethods.cs +++ b/src/Shared/EnumerableMethods.cs @@ -249,7 +249,9 @@ public static MethodInfo GetMinWithoutSelector(Type type) public static MethodInfo GetMinWithSelector(Type type) => MinWithSelectorMethods.GetValueOrDefault(type, MinWithSelector); - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Types used here in 'MakeGenericType' are types like 'TSource', not specific types.")] + [UnconditionalSuppressMessage( + "AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = "Types used here in 'MakeGenericType' are types like 'TSource', not specific types.")] static EnumerableMethods() { var queryableMethodGroups = typeof(Enumerable) @@ -600,10 +602,9 @@ static EnumerableMethods() } MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) - => queryableMethodGroups[name].Single( - mi => ((genericParameterCount == 0 && !mi.IsGenericMethod) - || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) - && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( - parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : []))); + => queryableMethodGroups[name].Single(mi => ((genericParameterCount == 0 && !mi.IsGenericMethod) + || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) + && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( + parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : []))); } } diff --git a/src/Shared/ExpressionExtensions.cs b/src/Shared/ExpressionExtensions.cs index 0835ed7eb3f..eeb6f0f9ad8 100644 --- a/src/Shared/ExpressionExtensions.cs +++ b/src/Shared/ExpressionExtensions.cs @@ -55,15 +55,15 @@ public static T GetConstantValue(this Expression expression) _ => throw new InvalidOperationException() }; - public static bool TryGetNonNullConstantValue(this Expression expression, [NotNullWhen(true)][MaybeNullWhen(false)]out T value) + public static bool TryGetNonNullConstantValue(this Expression expression, [NotNullWhen(true), MaybeNullWhen(false)] out T value) { switch (expression) { - case ConstantExpression constant when constant.Value is T typedValue: + case ConstantExpression { Value: T typedValue }: value = typedValue; return true; #pragma warning disable EF9100 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - case LiftableConstantExpression liftableConstant when liftableConstant.OriginalExpression.Value is T typedValue: + case LiftableConstantExpression { OriginalExpression.Value: T typedValue }: #pragma warning restore EF9100 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. value = typedValue; return true; diff --git a/src/Shared/ExpressionVisitorExtensions.cs b/src/Shared/ExpressionVisitorExtensions.cs index 5ca301ad3ec..85b946bc9eb 100644 --- a/src/Shared/ExpressionVisitorExtensions.cs +++ b/src/Shared/ExpressionVisitorExtensions.cs @@ -1,14 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// ReSharper disable once CheckNamespace +#nullable enable using System.Runtime.CompilerServices; +// ReSharper disable once CheckNamespace namespace System.Linq.Expressions; -#nullable enable - [DebuggerStepThrough] internal static class ExpressionVisitorExtensions { diff --git a/src/Shared/HashHelpers.cs b/src/Shared/HashHelpers.cs index 54de715c314..4a3d6d63e2c 100644 --- a/src/Shared/HashHelpers.cs +++ b/src/Shared/HashHelpers.cs @@ -3,117 +3,120 @@ #nullable enable -namespace Microsoft.EntityFrameworkCore.Utilities +namespace Microsoft.EntityFrameworkCore.Utilities; + +internal static class HashHelpers { - internal static partial class HashHelpers + internal static int PowerOf2(int v) { - internal static int PowerOf2(int v) + if ((v & (v - 1)) == 0) { - if ((v & (v - 1)) == 0) - { - return v; - } - - var i = 2; - while (i < v) - { - i <<= 1; - } + return v; + } - return i; + var i = 2; + while (i < v) + { + i <<= 1; } - // must never be written to - internal static readonly int[] SizeOneIntArray = new int[1]; - - public const int HashCollisionThreshold = 100; - - // This is the maximum prime smaller than Array.MaxArrayLength - public const int MaxPrimeArrayLength = 0x7FEFFFFD; - - public const int HashPrime = 101; - - // Table of prime numbers to use as hash table sizes. - // A typical resize algorithm would pick the smallest prime number in this array - // that is larger than twice the previous capacity. - // Suppose our Hashtable currently has capacity x and enough elements are added - // such that a resize needs to occur. Resizing first computes 2x then finds the - // first prime in the table greater than 2x, i.e. if primes are ordered - // p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n. - // Doubling is important for preserving the asymptotic complexity of the - // hashtable operations such as add. Having a prime guarantees that double - // hashing does not lead to infinite loops. IE, your hash function will be - // h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime. - // We prefer the low computation costs of higher prime numbers over the increased - // memory allocation of a fixed prime number i.e. when right sizing a HashSet. - public static readonly int[] primes = - [ - 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, - 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, - 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, - 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, - 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 - ]; - - public static bool IsPrime(int candidate) + return i; + } + + // must never be written to + internal static readonly int[] SizeOneIntArray = new int[1]; + + public const int HashCollisionThreshold = 100; + + // This is the maximum prime smaller than Array.MaxArrayLength + public const int MaxPrimeArrayLength = 0x7FEFFFFD; + + public const int HashPrime = 101; + + // Table of prime numbers to use as hash table sizes. + // A typical resize algorithm would pick the smallest prime number in this array + // that is larger than twice the previous capacity. + // Suppose our Hashtable currently has capacity x and enough elements are added + // such that a resize needs to occur. Resizing first computes 2x then finds the + // first prime in the table greater than 2x, i.e. if primes are ordered + // p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n. + // Doubling is important for preserving the asymptotic complexity of the + // hashtable operations such as add. Having a prime guarantees that double + // hashing does not lead to infinite loops. IE, your hash function will be + // h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime. + // We prefer the low computation costs of higher prime numbers over the increased + // memory allocation of a fixed prime number i.e. when right sizing a HashSet. + public static readonly int[] primes = + [ + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, + 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, + 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 + ]; + + public static bool IsPrime(int candidate) + { + if ((candidate & 1) != 0) { - if ((candidate & 1) != 0) + var limit = (int)Math.Sqrt(candidate); + for (var divisor = 3; divisor <= limit; divisor += 2) { - var limit = (int)Math.Sqrt(candidate); - for (var divisor = 3; divisor <= limit; divisor += 2) + if ((candidate % divisor) == 0) { - if ((candidate % divisor) == 0) - { - return false; - } + return false; } - return true; } - return candidate == 2; + + return true; } - public static int GetPrime(int min) + return candidate == 2; + } + + public static int GetPrime(int min) + { + if (min < 0) { - if (min < 0) - { - throw new ArgumentException("Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table."); - } + throw new ArgumentException( + "Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table."); + } - for (var i = 0; i < primes.Length; i++) + for (var i = 0; i < primes.Length; i++) + { + var prime = primes[i]; + if (prime >= min) { - var prime = primes[i]; - if (prime >= min) - { - return prime; - } + return prime; } + } - //outside of our predefined table. - //compute the hard way. - for (var i = (min | 1); i < int.MaxValue; i += 2) + //outside of our predefined table. + //compute the hard way. + for (var i = (min | 1); i < int.MaxValue; i += 2) + { + if (IsPrime(i) && ((i - 1) % HashPrime != 0)) { - if (IsPrime(i) && ((i - 1) % HashPrime != 0)) - { - return i; - } + return i; } - return min; } - // Returns size of hashtable to grow to. - public static int ExpandPrime(int oldSize) - { - var newSize = 2 * oldSize; + return min; + } - // Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow. - // Note that this check works even when _items.Length overflowed thanks to the (uint) cast - if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize) - { - Check.DebugAssert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength"); - return MaxPrimeArrayLength; - } + // Returns size of hashtable to grow to. + public static int ExpandPrime(int oldSize) + { + var newSize = 2 * oldSize; - return GetPrime(newSize); + // Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow. + // Note that this check works even when _items.Length overflowed thanks to the (uint) cast + if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize) + { + Check.DebugAssert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength"); + return MaxPrimeArrayLength; } + + return GetPrime(newSize); } } diff --git a/src/Shared/IDictionaryDebugView.cs b/src/Shared/IDictionaryDebugView.cs index c31493c4367..2db698b9f97 100644 --- a/src/Shared/IDictionaryDebugView.cs +++ b/src/Shared/IDictionaryDebugView.cs @@ -3,53 +3,52 @@ #nullable enable -namespace Microsoft.EntityFrameworkCore.Utilities +namespace Microsoft.EntityFrameworkCore.Utilities; + +internal sealed class IDictionaryDebugView(IDictionary dictionary) { - internal sealed class IDictionaryDebugView(IDictionary dictionary) - { - private readonly IDictionary _dict = dictionary ?? throw new ArgumentNullException(nameof(dictionary)); + private readonly IDictionary _dict = dictionary ?? throw new ArgumentNullException(nameof(dictionary)); - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public KeyValuePair[] Items + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public KeyValuePair[] Items + { + get { - get - { - var items = new KeyValuePair[_dict.Count]; - _dict.CopyTo(items, 0); - return items; - } + var items = new KeyValuePair[_dict.Count]; + _dict.CopyTo(items, 0); + return items; } } +} - internal sealed class DictionaryKeyCollectionDebugView(ICollection collection) - { - private readonly ICollection _collection = collection ?? throw new ArgumentNullException(nameof(collection)); +internal sealed class DictionaryKeyCollectionDebugView(ICollection collection) +{ + private readonly ICollection _collection = collection ?? throw new ArgumentNullException(nameof(collection)); - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public TKey[] Items + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public TKey[] Items + { + get { - get - { - var items = new TKey[_collection.Count]; - _collection.CopyTo(items, 0); - return items; - } + var items = new TKey[_collection.Count]; + _collection.CopyTo(items, 0); + return items; } } +} - internal sealed class DictionaryValueCollectionDebugView(ICollection collection) - { - private readonly ICollection _collection = collection ?? throw new ArgumentNullException(nameof(collection)); +internal sealed class DictionaryValueCollectionDebugView(ICollection collection) +{ + private readonly ICollection _collection = collection ?? throw new ArgumentNullException(nameof(collection)); - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public TValue[] Items + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public TValue[] Items + { + get { - get - { - var items = new TValue[_collection.Count]; - _collection.CopyTo(items, 0); - return items; - } + var items = new TValue[_collection.Count]; + _collection.CopyTo(items, 0); + return items; } } } diff --git a/src/Shared/MethodInfoExtensions.cs b/src/Shared/MethodInfoExtensions.cs index 1d86c668bed..58f96963e28 100644 --- a/src/Shared/MethodInfoExtensions.cs +++ b/src/Shared/MethodInfoExtensions.cs @@ -10,11 +10,10 @@ internal static class MethodInfoExtensions { public static bool IsContainsMethod(this MethodInfo method) => method is { Name: nameof(IList.Contains), DeclaringType: not null } - && method.DeclaringType.GetInterfaces().Append(method.DeclaringType).Any( - t => t == typeof(IList) - || (t.IsGenericType - && t.GetGenericTypeDefinition() is Type genericType - && (genericType == typeof(ICollection<>) - || genericType == typeof(IReadOnlySet<>) - || genericType == typeof(IImmutableSet<>)))); + && method.DeclaringType.GetInterfaces().Append(method.DeclaringType).Any(t => t == typeof(IList) + || (t.IsGenericType + && t.GetGenericTypeDefinition() is { } genericType + && (genericType == typeof(ICollection<>) + || genericType == typeof(IReadOnlySet<>) + || genericType == typeof(IImmutableSet<>)))); } diff --git a/src/Shared/Multigraph.cs b/src/Shared/Multigraph.cs index 05c5187ae79..be02a1d68b6 100644 --- a/src/Shared/Multigraph.cs +++ b/src/Shared/Multigraph.cs @@ -18,9 +18,7 @@ public Multigraph() } public Multigraph(IComparer secondarySortComparer) - { - _secondarySortComparer = secondarySortComparer; - } + => _secondarySortComparer = secondarySortComparer; public Multigraph(Comparison secondarySortComparer) : this(Comparer.Create(secondarySortComparer)) @@ -33,11 +31,11 @@ public IEnumerable GetEdges(TVertex from, TVertex to) { if (successorSet.TryGetValue(to, out var edges)) { - return edges is IEnumerable edgeList ? edgeList.Select(e => e.Payload) : (new[] { ((Edge)edges!).Payload }); + return edges is IEnumerable edgeList ? edgeList.Select(e => e.Payload) : ( [((Edge)edges!).Payload]); } } - return Enumerable.Empty(); + return []; } public void AddVertex(TVertex vertex) @@ -249,9 +247,8 @@ private IReadOnlyList> TopologicalSortCore( // Find a vertex in the unsorted portion of the graph that has edges to the candidate var incomingNeighbor = GetIncomingNeighbors(candidateVertex) - .First( - neighbor => predecessorCounts.TryGetValue(neighbor, out var neighborPredecessors) - && neighborPredecessors > 0); + .First(neighbor => predecessorCounts.TryGetValue(neighbor, out var neighborPredecessors) + && neighborPredecessors > 0); if (canBreakEdges(incomingNeighbor, candidateVertex, GetEdges(incomingNeighbor, candidateVertex))) { @@ -279,8 +276,8 @@ private IReadOnlyList> TopologicalSortCore( continue; } - var currentCycleVertex = _vertices.First( - v => predecessorCounts.TryGetValue(v, out var predecessorCount) && predecessorCount != 0); + var currentCycleVertex = + _vertices.First(v => predecessorCounts.TryGetValue(v, out var predecessorCount) && predecessorCount != 0); var cycle = new List { currentCycleVertex }; var finished = false; while (!finished) @@ -330,11 +327,10 @@ private IReadOnlyList> TopologicalSortCore( void CheckBatchingBoundary(TVertex vertex) { if (withBatching - && _predecessorMap[vertex].Any( - kv => - (kv.Value is Edge { RequiresBatchingBoundary: true } - || kv.Value is IEnumerable edges && edges.Any(e => e.RequiresBatchingBoundary)) - && currentBatchSet.Contains(kv.Key))) + && _predecessorMap[vertex].Any(kv => + (kv.Value is Edge { RequiresBatchingBoundary: true } + || kv.Value is IEnumerable edges && edges.Any(e => e.RequiresBatchingBoundary)) + && currentBatchSet.Contains(kv.Key))) { batchBoundaryRequired = true; } diff --git a/src/Shared/OrderedDictionary.KeyCollection.cs b/src/Shared/OrderedDictionary.KeyCollection.cs index 401aec343ea..48bea986fa6 100644 --- a/src/Shared/OrderedDictionary.KeyCollection.cs +++ b/src/Shared/OrderedDictionary.KeyCollection.cs @@ -5,155 +5,178 @@ using System.Collections; -namespace Microsoft.EntityFrameworkCore.Utilities +namespace Microsoft.EntityFrameworkCore.Utilities; + +internal partial class OrderedDictionary { - internal partial class OrderedDictionary + /// + /// Represents the collection of keys in a . This class cannot be inherited. + /// + [DebuggerTypeProxy(typeof(DictionaryKeyCollectionDebugView<,>))] + [DebuggerDisplay("Count = {Count}")] + internal sealed class KeyCollection : IList, IReadOnlyList { + private readonly OrderedDictionary _orderedDictionary; + /// - /// Represents the collection of keys in a . This class cannot be inherited. + /// Gets the number of elements contained in the . /// - [DebuggerTypeProxy(typeof(DictionaryKeyCollectionDebugView<,>))] - [DebuggerDisplay("Count = {Count}")] - internal sealed class KeyCollection : IList, IReadOnlyList - { - private readonly OrderedDictionary _orderedDictionary; + /// The number of elements contained in the . + public int Count + => _orderedDictionary.Count; - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count => _orderedDictionary.Count; - - /// - /// Gets the key at the specified index as an O(1) operation. - /// - /// The zero-based index of the key to get. - /// The key at the specified index. - /// is less than 0.-or- is equal to or greater than . - public TKey this[int index] => ((IList>)_orderedDictionary)[index].Key; + /// + /// Gets the key at the specified index as an O(1) operation. + /// + /// The zero-based index of the key to get. + /// The key at the specified index. + /// + /// is less than 0.-or- is equal to or greater + /// than . + /// + public TKey this[int index] + => ((IList>)_orderedDictionary)[index].Key; + + TKey IList.this[int index] + { + get => this[index]; + set => throw new NotSupportedException(); + } - TKey IList.this[int index] - { - get => this[index]; - set => throw new NotSupportedException(); - } + bool ICollection.IsReadOnly + => true; - bool ICollection.IsReadOnly => true; + internal KeyCollection(OrderedDictionary orderedDictionary) + => _orderedDictionary = orderedDictionary; - internal KeyCollection(OrderedDictionary orderedDictionary) - { - _orderedDictionary = orderedDictionary; - } + /// + /// Returns an enumerator that iterates through the . + /// + /// + /// A for the + /// . + /// + public Enumerator GetEnumerator() + => new(_orderedDictionary); - /// - /// Returns an enumerator that iterates through the . - /// - /// A for the . - public Enumerator GetEnumerator() => new Enumerator(_orderedDictionary); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + int IList.IndexOf(TKey item) + => _orderedDictionary.IndexOf(item); - int IList.IndexOf(TKey item) => _orderedDictionary.IndexOf(item); + void IList.Insert(int index, TKey item) + => throw new NotSupportedException(); - void IList.Insert(int index, TKey item) => throw new NotSupportedException(); + void IList.RemoveAt(int index) + => throw new NotSupportedException(); - void IList.RemoveAt(int index) => throw new NotSupportedException(); + void ICollection.Add(TKey item) + => throw new NotSupportedException(); - void ICollection.Add(TKey item) => throw new NotSupportedException(); + void ICollection.Clear() + => throw new NotSupportedException(); - void ICollection.Clear() => throw new NotSupportedException(); + bool ICollection.Contains(TKey item) + => _orderedDictionary.ContainsKey(item); - bool ICollection.Contains(TKey item) => _orderedDictionary.ContainsKey(item); + void ICollection.CopyTo(TKey[] array, int arrayIndex) + { + ArgumentNullException.ThrowIfNull(array); + if ((uint)arrayIndex > (uint)array.Length) + { + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + } - void ICollection.CopyTo(TKey[] array, int arrayIndex) + var count = Count; + if (array.Length - arrayIndex < count) { - ArgumentNullException.ThrowIfNull(array); - if ((uint)arrayIndex > (uint)array.Length) - { - throw new ArgumentOutOfRangeException(nameof(arrayIndex)); - } - var count = Count; - if (array.Length - arrayIndex < count) - { - throw new ArgumentException(); - } + throw new ArgumentException(); + } - var entries = _orderedDictionary._entries; - for (var i = 0; i < count; ++i) - { - array[i + arrayIndex] = entries[i].Key; - } + var entries = _orderedDictionary._entries; + for (var i = 0; i < count; ++i) + { + array[i + arrayIndex] = entries[i].Key; } + } + + bool ICollection.Remove(TKey item) + => throw new NotSupportedException(); - bool ICollection.Remove(TKey item) => throw new NotSupportedException(); + /// + /// Enumerates the elements of a . + /// + public struct Enumerator : IEnumerator + { + private readonly OrderedDictionary _orderedDictionary; + private readonly int _version; + private int _index; + private TKey _current; /// - /// Enumerates the elements of a . + /// Gets the element at the current position of the enumerator. /// - public struct Enumerator : IEnumerator - { - private readonly OrderedDictionary _orderedDictionary; - private readonly int _version; - private int _index; - private TKey _current; + /// The element in the at the current position of the enumerator. + public readonly TKey Current + => _current; - /// - /// Gets the element at the current position of the enumerator. - /// - /// The element in the at the current position of the enumerator. - public readonly TKey Current => _current; + readonly object? IEnumerator.Current + => _current; + + internal Enumerator(OrderedDictionary orderedDictionary) + { + _orderedDictionary = orderedDictionary; + _version = orderedDictionary._version; + _index = 0; + _current = default!; + } - readonly object? IEnumerator.Current => _current; + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + } - internal Enumerator(OrderedDictionary orderedDictionary) + /// + /// Advances the enumerator to the next element of the . + /// + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the + /// collection. + /// + /// The collection was modified after the enumerator was created. + public bool MoveNext() + { + if (_version != _orderedDictionary._version) { - _orderedDictionary = orderedDictionary; - _version = orderedDictionary._version; - _index = 0; - _current = default!; + throw new InvalidOperationException(); } - /// - /// Releases all resources used by the . - /// - public void Dispose() + if (_index < _orderedDictionary.Count) { + _current = _orderedDictionary._entries[_index].Key; + ++_index; + return true; } - /// - /// Advances the enumerator to the next element of the . - /// - /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. - /// The collection was modified after the enumerator was created. - public bool MoveNext() - { - if (_version != _orderedDictionary._version) - { - throw new InvalidOperationException(); - } - - if (_index < _orderedDictionary.Count) - { - _current = _orderedDictionary._entries[_index].Key; - ++_index; - return true; - } - _current = default!; - return false; - } + _current = default!; + return false; + } - void IEnumerator.Reset() + void IEnumerator.Reset() + { + if (_version != _orderedDictionary._version) { - if (_version != _orderedDictionary._version) - { - throw new InvalidOperationException(); - } - - _index = 0; - _current = default!; + throw new InvalidOperationException(); } + + _index = 0; + _current = default!; } } } diff --git a/src/Shared/OrderedDictionary.ValueCollection.cs b/src/Shared/OrderedDictionary.ValueCollection.cs index 71ead29c182..1c89df5b231 100644 --- a/src/Shared/OrderedDictionary.ValueCollection.cs +++ b/src/Shared/OrderedDictionary.ValueCollection.cs @@ -5,169 +5,192 @@ using System.Collections; -namespace Microsoft.EntityFrameworkCore.Utilities +namespace Microsoft.EntityFrameworkCore.Utilities; + +internal partial class OrderedDictionary { - internal partial class OrderedDictionary + /// + /// Represents the collection of values in a . This class cannot be inherited. + /// + [DebuggerTypeProxy(typeof(DictionaryValueCollectionDebugView<,>))] + [DebuggerDisplay("Count = {Count}")] + public sealed class ValueCollection : IList, IReadOnlyList { + private readonly OrderedDictionary _orderedDictionary; + /// - /// Represents the collection of values in a . This class cannot be inherited. + /// Gets the number of elements contained in the . /// - [DebuggerTypeProxy(typeof(DictionaryValueCollectionDebugView<,>))] - [DebuggerDisplay("Count = {Count}")] - public sealed class ValueCollection : IList, IReadOnlyList - { - private readonly OrderedDictionary _orderedDictionary; + /// The number of elements contained in the . + public int Count + => _orderedDictionary.Count; - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count => _orderedDictionary.Count; - - /// - /// Gets the value at the specified index as an O(1) operation. - /// - /// The zero-based index of the value to get. - /// The value at the specified index. - /// is less than 0.-or- is equal to or greater than . - public TValue this[int index] => _orderedDictionary[index]; + /// + /// Gets the value at the specified index as an O(1) operation. + /// + /// The zero-based index of the value to get. + /// The value at the specified index. + /// + /// is less than 0.-or- is equal to or greater + /// than . + /// + public TValue this[int index] + => _orderedDictionary[index]; + + TValue IList.this[int index] + { + get => this[index]; + set => throw new NotSupportedException(); + } - TValue IList.this[int index] - { - get => this[index]; - set => throw new NotSupportedException(); - } + bool ICollection.IsReadOnly + => true; - bool ICollection.IsReadOnly => true; + internal ValueCollection(OrderedDictionary orderedDictionary) + => _orderedDictionary = orderedDictionary; - internal ValueCollection(OrderedDictionary orderedDictionary) - { - _orderedDictionary = orderedDictionary; - } - - /// - /// Returns an enumerator that iterates through the . - /// - /// A for the . - public Enumerator GetEnumerator() => new Enumerator(_orderedDictionary); + /// + /// Returns an enumerator that iterates through the . + /// + /// + /// A for the + /// . + /// + public Enumerator GetEnumerator() + => new(_orderedDictionary); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - int IList.IndexOf(TValue item) + int IList.IndexOf(TValue item) + { + var comparer = EqualityComparer.Default; + var entries = _orderedDictionary._entries; + var count = Count; + for (var i = 0; i < count; ++i) { - var comparer = EqualityComparer.Default; - var entries = _orderedDictionary._entries; - var count = Count; - for (var i = 0; i < count; ++i) + if (comparer.Equals(entries[i].Value, item)) { - if (comparer.Equals(entries[i].Value, item)) - { - return i; - } + return i; } - return -1; } - void IList.Insert(int index, TValue item) => throw new NotSupportedException(); + return -1; + } + + void IList.Insert(int index, TValue item) + => throw new NotSupportedException(); - void IList.RemoveAt(int index) => throw new NotSupportedException(); + void IList.RemoveAt(int index) + => throw new NotSupportedException(); - void ICollection.Add(TValue item) => throw new NotSupportedException(); + void ICollection.Add(TValue item) + => throw new NotSupportedException(); - void ICollection.Clear() => throw new NotSupportedException(); + void ICollection.Clear() + => throw new NotSupportedException(); - bool ICollection.Contains(TValue item) => ((IList)this).IndexOf(item) >= 0; + bool ICollection.Contains(TValue item) + => ((IList)this).IndexOf(item) >= 0; + + void ICollection.CopyTo(TValue[] array, int arrayIndex) + { + ArgumentNullException.ThrowIfNull(array); - void ICollection.CopyTo(TValue[] array, int arrayIndex) + if ((uint)arrayIndex > (uint)array.Length) { - ArgumentNullException.ThrowIfNull(array); + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + } - if ((uint)arrayIndex > (uint)array.Length) - { - throw new ArgumentOutOfRangeException(nameof(arrayIndex)); - } - var count = Count; - if (array.Length - arrayIndex < count) - { - throw new ArgumentException(); - } + var count = Count; + if (array.Length - arrayIndex < count) + { + throw new ArgumentException(); + } - var entries = _orderedDictionary._entries; - for (var i = 0; i < count; ++i) - { - array[i + arrayIndex] = entries[i].Value; - } + var entries = _orderedDictionary._entries; + for (var i = 0; i < count; ++i) + { + array[i + arrayIndex] = entries[i].Value; } + } - bool ICollection.Remove(TValue item) => throw new NotSupportedException(); + bool ICollection.Remove(TValue item) + => throw new NotSupportedException(); + + /// + /// Enumerates the elements of a . + /// + public struct Enumerator : IEnumerator + { + private readonly OrderedDictionary _orderedDictionary; + private readonly int _version; + private int _index; + private TValue _current; /// - /// Enumerates the elements of a . + /// Gets the element at the current position of the enumerator. /// - public struct Enumerator : IEnumerator - { - private readonly OrderedDictionary _orderedDictionary; - private readonly int _version; - private int _index; - private TValue _current; + /// The element in the at the current position of the enumerator. + public TValue Current + => _current; - /// - /// Gets the element at the current position of the enumerator. - /// - /// The element in the at the current position of the enumerator. - public TValue Current => _current; + object? IEnumerator.Current + => _current; - object? IEnumerator.Current => _current; + internal Enumerator(OrderedDictionary orderedDictionary) + { + _orderedDictionary = orderedDictionary; + _version = orderedDictionary._version; + _index = 0; + _current = default!; + } - internal Enumerator(OrderedDictionary orderedDictionary) - { - _orderedDictionary = orderedDictionary; - _version = orderedDictionary._version; - _index = 0; - _current = default!; - } + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + } - /// - /// Releases all resources used by the . - /// - public void Dispose() + /// + /// Advances the enumerator to the next element of the . + /// + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the + /// collection. + /// + /// The collection was modified after the enumerator was created. + public bool MoveNext() + { + if (_version != _orderedDictionary._version) { + throw new InvalidOperationException(); } - /// - /// Advances the enumerator to the next element of the . - /// - /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. - /// The collection was modified after the enumerator was created. - public bool MoveNext() + if (_index < _orderedDictionary.Count) { - if (_version != _orderedDictionary._version) - { - throw new InvalidOperationException(); - } - - if (_index < _orderedDictionary.Count) - { - _current = _orderedDictionary._entries[_index].Value; - ++_index; - return true; - } - _current = default!; - return false; + _current = _orderedDictionary._entries[_index].Value; + ++_index; + return true; } - void IEnumerator.Reset() - { - if (_version != _orderedDictionary._version) - { - throw new InvalidOperationException(); - } + _current = default!; + return false; + } - _index = 0; - _current = default!; + void IEnumerator.Reset() + { + if (_version != _orderedDictionary._version) + { + throw new InvalidOperationException(); } + + _index = 0; + _current = default!; } } } diff --git a/src/Shared/OrderedDictionary.cs b/src/Shared/OrderedDictionary.cs index 9fbf1e9717b..b735bd60a32 100644 --- a/src/Shared/OrderedDictionary.cs +++ b/src/Shared/OrderedDictionary.cs @@ -4,898 +4,1039 @@ #nullable enable using System.Collections; - -namespace Microsoft.EntityFrameworkCore.Utilities +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.EntityFrameworkCore.Utilities; + +/// +/// Represents an ordered collection of keys and values with the same performance as with O(1) +/// lookups and adds but with O(n) inserts and removes. +/// +/// The type of the keys in the dictionary. +/// The type of the values in the dictionary. +[DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] +[DebuggerDisplay("Count = {Count}")] +internal sealed partial class OrderedDictionary : IDictionary, + IReadOnlyDictionary, + IList>, + IReadOnlyList> { - /// - /// Represents an ordered collection of keys and values with the same performance as with O(1) lookups and adds but with O(n) inserts and removes. - /// - /// The type of the keys in the dictionary. - /// The type of the values in the dictionary. - [DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] - [DebuggerDisplay("Count = {Count}")] - internal sealed partial class OrderedDictionary : IDictionary, IReadOnlyDictionary, IList>, IReadOnlyList> - { - private struct Entry - { - public uint HashCode; - public TKey Key; - public TValue Value; - public int Next; // the index of the next item in the same bucket, -1 if last - } - - // We want to initialize without allocating arrays. We also want to avoid null checks. - // Array.Empty would give divide by zero in modulo operation. So we use static one element arrays. - // The first add will cause a resize replacing these with real arrays of three elements. - // Arrays are wrapped in a class to avoid being duplicated for each - private static readonly Entry[] InitialEntries = new Entry[1]; - // 1-based index into _entries; 0 means empty - private int[] _buckets = HashHelpers.SizeOneIntArray; - // remains contiguous and maintains order - private Entry[] _entries = InitialEntries; - private int _count; - private int _version; - // is null when comparer is EqualityComparer.Default so that the GetHashCode method is used explicitly on the object - private readonly IEqualityComparer? _comparer; - private KeyCollection? _keys; - private ValueCollection? _values; + private struct Entry + { + public uint HashCode; + public TKey Key; + public TValue Value; + public int Next; // the index of the next item in the same bucket, -1 if last + } - /// - /// Gets the number of key/value pairs contained in the . - /// - /// The number of key/value pairs contained in the . - public int Count => _count; + // We want to initialize without allocating arrays. We also want to avoid null checks. + // Array.Empty would give divide by zero in modulo operation. So we use static one element arrays. + // The first add will cause a resize replacing these with real arrays of three elements. + // Arrays are wrapped in a class to avoid being duplicated for each + private static readonly Entry[] InitialEntries = new Entry[1]; - /// - /// Gets the that is used to determine equality of keys for the dictionary. - /// - /// The generic interface implementation that is used to determine equality of keys for the current and to provide hash values for the keys. - public IEqualityComparer Comparer => _comparer ?? EqualityComparer.Default; + // 1-based index into _entries; 0 means empty + private int[] _buckets = HashHelpers.SizeOneIntArray; - /// - /// Gets a collection containing the keys in the . - /// - /// An containing the keys in the . - public KeyCollection Keys => _keys ??= new KeyCollection(this); + // remains contiguous and maintains order + private Entry[] _entries = InitialEntries; + private int _count; - /// - /// Gets a collection containing the values in the . - /// - /// An containing the values in the . - public ValueCollection Values => _values ??= new ValueCollection(this); + private int _version; - /// - /// Gets or sets the value associated with the specified key as an O(1) operation. - /// - /// The key of the value to get or set. - /// The value associated with the specified key. If the specified key is not found, a get operation throws a , and a set operation creates a new element with the specified key. - /// is null. - /// The property is retrieved and does not exist in the collection. - public TValue this[TKey key] + // is null when comparer is EqualityComparer.Default so that the GetHashCode method is used explicitly on the object + private readonly IEqualityComparer? _comparer; + + /// + /// Gets the number of key/value pairs contained in the . + /// + /// The number of key/value pairs contained in the . + public int Count + => _count; + + /// + /// Gets the that is used to determine equality of keys for the dictionary. + /// + /// + /// The generic interface implementation that is used to determine equality of keys for the + /// current and to provide hash values for the keys. + /// + public IEqualityComparer Comparer + => _comparer ?? EqualityComparer.Default; + + /// + /// Gets a collection containing the keys in the . + /// + /// + /// An containing the keys in the + /// . + /// + [field: AllowNull, MaybeNull] + public KeyCollection Keys + => field ??= new KeyCollection(this); + + /// + /// Gets a collection containing the values in the . + /// + /// + /// An containing the values in the + /// . + /// + [field: AllowNull, MaybeNull] + public ValueCollection Values + => field ??= new ValueCollection(this); + + /// + /// Gets or sets the value associated with the specified key as an O(1) operation. + /// + /// The key of the value to get or set. + /// + /// The value associated with the specified key. If the specified key is not found, a get operation throws a + /// , and a set operation creates a new element with the specified key. + /// + /// is null. + /// The property is retrieved and does not exist in the collection. + public TValue this[TKey key] + { + get { - get - { - var index = IndexOf(key); - return index < 0 - ? throw new KeyNotFoundException($"Key {key} not found in the dictionary") - : _entries[index].Value; - } - set => TryInsert(null, key, value, InsertionBehavior.OverwriteExisting); + var index = IndexOf(key); + return index < 0 + ? throw new KeyNotFoundException($"Key {key} not found in the dictionary") + : _entries[index].Value; } + set => TryInsert(null, key, value, InsertionBehavior.OverwriteExisting); + } - /// - /// Gets or sets the value at the specified index as an O(1) operation. - /// - /// The zero-based index of the element to get or set. - /// The value at the specified index. - /// is less than 0.-or- is equal to or greater than . - public TValue this[int index] + /// + /// Gets or sets the value at the specified index as an O(1) operation. + /// + /// The zero-based index of the element to get or set. + /// The value at the specified index. + /// + /// is less than 0.-or- is equal to or greater + /// than . + /// + public TValue this[int index] + { + get { - get - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); - return _entries[index].Value; - } - set - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); + return _entries[index].Value; + } + set + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); - _entries[index].Value = value; - } + _entries[index].Value = value; } + } - /// - /// Initializes a new instance of the class that is empty, has the default initial capacity, and uses the default equality comparer for the key type. - /// - public OrderedDictionary() - : this(0, null) + /// + /// Initializes a new instance of the class that is empty, has the default initial capacity, + /// and uses the default equality comparer for the key type. + /// + public OrderedDictionary() + : this(0, null) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the specified initial + /// capacity, and uses the default equality comparer for the key type. + /// + /// The initial number of elements that the can contain. + /// is less than 0. + public OrderedDictionary(int capacity) + : this(capacity, null) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the default initial capacity, + /// and uses the specified . + /// + /// + /// The implementation to use when comparing keys, or null to use the default + /// for the type of the key. + /// + public OrderedDictionary(IEqualityComparer comparer) + : this(0, comparer) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the specified initial + /// capacity, and uses the specified . + /// + /// The initial number of elements that the can contain. + /// + /// The implementation to use when comparing keys, or null to use the default + /// for the type of the key. + /// + /// is less than 0. + public OrderedDictionary(int capacity, IEqualityComparer? comparer) + { + ArgumentOutOfRangeException.ThrowIfNegative(capacity); + + if (capacity > 0) { + var newSize = HashHelpers.GetPrime(capacity); + _buckets = new int[newSize]; + _entries = new Entry[newSize]; } - /// - /// Initializes a new instance of the class that is empty, has the specified initial capacity, and uses the default equality comparer for the key type. - /// - /// The initial number of elements that the can contain. - /// is less than 0. - public OrderedDictionary(int capacity) - : this(capacity, null) + if (comparer != EqualityComparer.Default) { + _comparer = comparer; } + } - /// - /// Initializes a new instance of the class that is empty, has the default initial capacity, and uses the specified . - /// - /// The implementation to use when comparing keys, or null to use the default for the type of the key. - public OrderedDictionary(IEqualityComparer comparer) - : this(0, comparer) + /// + /// Initializes a new instance of the class that contains elements copied from the specified + /// and uses the default equality comparer for the key type. + /// + /// + /// The whose elements are copied to the new + /// . + /// + /// is null. + /// contains one or more duplicate keys. + public OrderedDictionary(IEnumerable> collection) + : this(collection, null) + { + } + + /// + /// Initializes a new instance of the class that contains elements copied from the specified + /// and uses the specified . + /// + /// + /// The whose elements are copied to the new + /// . + /// + /// + /// The implementation to use when comparing keys, or null to use the default + /// for the type of the key. + /// + /// is null. + /// contains one or more duplicate keys. + public OrderedDictionary(IEnumerable> collection, IEqualityComparer? comparer) + : this((collection as ICollection>)?.Count ?? 0, comparer) + { + ArgumentNullException.ThrowIfNull(collection); + + foreach (var pair in collection) { + Add(pair.Key, pair.Value); } + } - /// - /// Initializes a new instance of the class that is empty, has the specified initial capacity, and uses the specified . - /// - /// The initial number of elements that the can contain. - /// The implementation to use when comparing keys, or null to use the default for the type of the key. - /// is less than 0. - public OrderedDictionary(int capacity, IEqualityComparer? comparer) + /// + /// Adds the specified key and value to the dictionary as an O(1) operation. + /// + /// The key of the element to add. + /// The value of the element to add. The value can be null for reference types. + /// is null. + /// An element with the same key already exists in the . + public void Add(TKey key, TValue value) + => TryInsert(null, key, value, InsertionBehavior.ThrowOnExisting); + + /// + /// Removes all keys and values from the . + /// + public void Clear() + { + if (_count > 0) { - ArgumentOutOfRangeException.ThrowIfNegative(capacity); + Array.Clear(_buckets, 0, _buckets.Length); + Array.Clear(_entries, 0, _count); + _count = 0; + ++_version; + } + } - if (capacity > 0) - { - var newSize = HashHelpers.GetPrime(capacity); - _buckets = new int[newSize]; - _entries = new Entry[newSize]; - } + /// + /// Determines whether the contains the specified key as an O(1) operation. + /// + /// The key to locate in the . + /// true if the contains an element with the specified key; otherwise, false. + /// is null. + public bool ContainsKey(TKey key) + => IndexOf(key) >= 0; - if (comparer != EqualityComparer.Default) - { - _comparer = comparer; - } - } + /// + /// Resizes the internal data structure if necessary to ensure no additional resizing to support the specified capacity. + /// + /// The number of elements that the must be able to contain. + /// The capacity of the . + /// is less than 0. + public int EnsureCapacity(int capacity) + { + ArgumentOutOfRangeException.ThrowIfNegative(capacity); - /// - /// Initializes a new instance of the class that contains elements copied from the specified and uses the default equality comparer for the key type. - /// - /// The whose elements are copied to the new . - /// is null. - /// contains one or more duplicate keys. - public OrderedDictionary(IEnumerable> collection) - : this(collection, null) + if (_entries.Length >= capacity) { + return _entries.Length; } - /// - /// Initializes a new instance of the class that contains elements copied from the specified and uses the specified . - /// - /// The whose elements are copied to the new . - /// The implementation to use when comparing keys, or null to use the default for the type of the key. - /// is null. - /// contains one or more duplicate keys. - public OrderedDictionary(IEnumerable> collection, IEqualityComparer? comparer) - : this((collection as ICollection>)?.Count ?? 0, comparer) - { - ArgumentNullException.ThrowIfNull(collection); + var newSize = HashHelpers.GetPrime(capacity); + Resize(newSize); + ++_version; + return newSize; + } - foreach (var pair in collection) - { - Add(pair.Key, pair.Value); - } - } + /// + /// Returns an enumerator that iterates through the . + /// + /// An structure for the . + public Enumerator GetEnumerator() + => new(this); - /// - /// Adds the specified key and value to the dictionary as an O(1) operation. - /// - /// The key of the element to add. - /// The value of the element to add. The value can be null for reference types. - /// is null. - /// An element with the same key already exists in the . - public void Add(TKey key, TValue value) => TryInsert(null, key, value, InsertionBehavior.ThrowOnExisting); + /// + /// Adds a key/value pair to the if the key does not already exist as an O(1) operation. + /// + /// The key of the element to add. + /// The value to be added, if the key does not already exist. + /// + /// The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new + /// value if the key was not in the dictionary. + /// + /// is null. + public TValue GetOrAdd(TKey key, TValue value) + => GetOrAdd(key, () => value); - /// - /// Removes all keys and values from the . - /// - public void Clear() + /// + /// Adds a key/value pair to the by using the specified function, if the key does not + /// already exist as an O(1) operation. + /// + /// The key of the element to add. + /// The function used to generate a value for the key. + /// + /// The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new + /// value for the key as returned by valueFactory if the key was not in the dictionary. + /// + /// is null.-or- is null. + public TValue GetOrAdd(TKey key, Func valueFactory) + { + ArgumentNullException.ThrowIfNull(valueFactory); + + var index = IndexOf(key, out var hashCode); + TValue value; + if (index < 0) { - if (_count > 0) - { - Array.Clear(_buckets, 0, _buckets.Length); - Array.Clear(_entries, 0, _count); - _count = 0; - ++_version; - } + value = valueFactory(); + AddInternal(null, key, value, hashCode); + } + else + { + value = _entries[index].Value; } - /// - /// Determines whether the contains the specified key as an O(1) operation. - /// - /// The key to locate in the . - /// true if the contains an element with the specified key; otherwise, false. - /// is null. - public bool ContainsKey(TKey key) => IndexOf(key) >= 0; + return value; + } - /// - /// Resizes the internal data structure if necessary to ensure no additional resizing to support the specified capacity. - /// - /// The number of elements that the must be able to contain. - /// The capacity of the . - /// is less than 0. - public int EnsureCapacity(int capacity) - { - ArgumentOutOfRangeException.ThrowIfNegative(capacity); + /// + /// Returns the zero-based index of the element with the specified key within the as an O(1) + /// operation. + /// + /// The key of the element to locate. + /// + /// The zero-based index of the element with the specified key within the , if found; + /// otherwise, -1. + /// + /// is null. + public int IndexOf(TKey key) + => IndexOf(key, out _); - if (_entries.Length >= capacity) - { - return _entries.Length; - } - var newSize = HashHelpers.GetPrime(capacity); - Resize(newSize); - ++_version; - return newSize; - } + /// + /// Inserts the specified key/value pair into the at the specified index as an O(n) + /// operation. + /// + /// The zero-based index of the key/value pair to insert. + /// The key of the element to insert. + /// The value of the element to insert. + /// is null. + /// An element with the same key already exists in the . + /// + /// is less than 0.-or- is greater than + /// . + /// + public void Insert(int index, TKey key, TValue value) + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(index, Count); - /// - /// Returns an enumerator that iterates through the . - /// - /// An structure for the . - public Enumerator GetEnumerator() => new Enumerator(this); + TryInsert(index, key, value, InsertionBehavior.ThrowOnExisting); + } - /// - /// Adds a key/value pair to the if the key does not already exist as an O(1) operation. - /// - /// The key of the element to add. - /// The value to be added, if the key does not already exist. - /// The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new value if the key was not in the dictionary. - /// is null. - public TValue GetOrAdd(TKey key, TValue value) => GetOrAdd(key, () => value); + /// + /// Inserts the element in this sorted dictionary to the corresponding index using the default comparer. + /// + /// The key of the element to insert. + /// The value of the element to insert. + public void Insert(TKey key, TValue value) + => Insert(key, value, Comparer.Default); - /// - /// Adds a key/value pair to the by using the specified function, if the key does not already exist as an O(1) operation. - /// - /// The key of the element to add. - /// The function used to generate a value for the key. - /// The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new value for the key as returned by valueFactory if the key was not in the dictionary. - /// is null.-or- is null. - public TValue GetOrAdd(TKey key, Func valueFactory) + /// + /// Inserts the element in this sorted dictionary to the corresponding index using the default comparer. + /// + /// The key of the element to insert. + /// The value of the element to insert. + /// The comparer to use. + public void Insert(TKey key, TValue value, IComparer comparer) + { + var existingIndex = IndexOf(key, out var hashCode); + if (existingIndex >= 0) { - ArgumentNullException.ThrowIfNull(valueFactory); + throw new ArgumentException($"Key {key} is already present"); + } - var index = IndexOf(key, out var hashCode); - TValue value; - if (index < 0) - { - value = valueFactory(); - AddInternal(null, key, value, hashCode); - } - else + for (var i = _count - 1; i >= 0; i--) + { + if (comparer.Compare(key, _entries[i].Key) >= 0) { - value = _entries[index].Value; + AddInternal(i + 1, key, value, hashCode); + return; } - return value; } - /// - /// Returns the zero-based index of the element with the specified key within the as an O(1) operation. - /// - /// The key of the element to locate. - /// The zero-based index of the element with the specified key within the , if found; otherwise, -1. - /// is null. - public int IndexOf(TKey key) => IndexOf(key, out _); + AddInternal(0, key, value, hashCode); + } - /// - /// Inserts the specified key/value pair into the at the specified index as an O(n) operation. - /// - /// The zero-based index of the key/value pair to insert. - /// The key of the element to insert. - /// The value of the element to insert. - /// is null. - /// An element with the same key already exists in the . - /// is less than 0.-or- is greater than . - public void Insert(int index, TKey key, TValue value) + /// + /// Moves the element at the specified fromIndex to the specified toIndex while re-arranging the elements in between. + /// + /// The zero-based index of the element to move. + /// The zero-based index to move the element to. + /// + /// is less than 0. + /// -or- + /// is equal to or greater than + /// -or- + /// is less than 0. + /// -or- + /// is equal to or greater than + /// + public void Move(int fromIndex, int toIndex) + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fromIndex, Count); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(toIndex, Count); + + if (fromIndex == toIndex) { - ArgumentOutOfRangeException.ThrowIfGreaterThan(index, Count); + return; + } - TryInsert(index, key, value, InsertionBehavior.ThrowOnExisting); + var entries = _entries; + var temp = entries[fromIndex]; + RemoveEntryFromBucket(fromIndex); + var direction = fromIndex < toIndex ? 1 : -1; + for (var i = fromIndex; i != toIndex; i += direction) + { + entries[i] = entries[i + direction]; + UpdateBucketIndex(i + direction, -direction); } - /// - /// Inserts the element in this sorted dictionary to the corresponding index using the default comparer. - /// - /// The key of the element to insert. - /// The value of the element to insert. - public void Insert(TKey key, TValue value) - => Insert(key, value, Comparer.Default); + AddEntryToBucket(ref temp, toIndex, _buckets); + entries[toIndex] = temp; + ++_version; + } - /// - /// Inserts the element in this sorted dictionary to the corresponding index using the default comparer. - /// - /// The key of the element to insert. - /// The value of the element to insert. - /// The comparer to use. - public void Insert(TKey key, TValue value, IComparer comparer) + /// + /// Moves the specified number of elements at the specified fromIndex to the specified toIndex while re-arranging the elements in between. + /// + /// The zero-based index of the elements to move. + /// The zero-based index to move the elements to. + /// The number of elements to move. + /// + /// is less than 0. + /// -or- + /// is equal to or greater than . + /// -or- + /// is less than 0. + /// -or- + /// is equal to or greater than . + /// -or- + /// is less than 0. + /// + /// + /// + is greater than . + /// -or- + /// + is greater than . + /// + public void MoveRange(int fromIndex, int toIndex, int count) + { + if (count == 1) { - var existingIndex = IndexOf(key, out var hashCode); - if (existingIndex >= 0) - { - throw new ArgumentException($"Key {key} is already present"); - } + Move(fromIndex, toIndex); + return; + } - for (var i = _count - 1; i >= 0; i--) - { - if (comparer.Compare(key, _entries[i].Key) >= 0) - { - AddInternal(i + 1, key, value, hashCode); - return; - } - } + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fromIndex, Count); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(toIndex, Count); + ArgumentOutOfRangeException.ThrowIfNegative(count); + ArgumentOutOfRangeException.ThrowIfGreaterThan(fromIndex + count, Count, nameof(fromIndex)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(toIndex + count, Count, nameof(toIndex)); - AddInternal(0, key, value, hashCode); + if (fromIndex == toIndex || count == 0) + { + return; } - /// - /// Moves the element at the specified fromIndex to the specified toIndex while re-arranging the elements in between. - /// - /// The zero-based index of the element to move. - /// The zero-based index to move the element to. - /// - /// is less than 0. - /// -or- - /// is equal to or greater than - /// -or- - /// is less than 0. - /// -or- - /// is equal to or greater than - /// - public void Move(int fromIndex, int toIndex) - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fromIndex, Count); - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(toIndex, Count); - - if (fromIndex == toIndex) - { - return; - } - - var entries = _entries; - var temp = entries[fromIndex]; - RemoveEntryFromBucket(fromIndex); - var direction = fromIndex < toIndex ? 1 : -1; - for (var i = fromIndex; i != toIndex; i += direction) - { - entries[i] = entries[i + direction]; - UpdateBucketIndex(i + direction, -direction); - } - AddEntryToBucket(ref temp, toIndex, _buckets); - entries[toIndex] = temp; - ++_version; + var entries = _entries; + // Make a copy of the entries to move. Consider using ArrayPool instead to avoid allocations? + var entriesToMove = new Entry[count]; + for (var i = 0; i < count; ++i) + { + entriesToMove[i] = entries[fromIndex + i]; + RemoveEntryFromBucket(fromIndex + i); } - /// - /// Moves the specified number of elements at the specified fromIndex to the specified toIndex while re-arranging the elements in between. - /// - /// The zero-based index of the elements to move. - /// The zero-based index to move the elements to. - /// The number of elements to move. - /// is less than 0. - /// -or- - /// is equal to or greater than . - /// -or- - /// is less than 0. - /// -or- - /// is equal to or greater than . - /// -or- - /// is less than 0. - /// + is greater than . - /// -or- - /// + is greater than . - public void MoveRange(int fromIndex, int toIndex, int count) - { - if (count == 1) - { - Move(fromIndex, toIndex); - return; - } + // Move entries in between + var direction = 1; + var amount = count; + var start = fromIndex; + var end = toIndex; + if (fromIndex > toIndex) + { + direction = -1; + amount = -count; + start = fromIndex + count - 1; + end = toIndex + count - 1; + } - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fromIndex, Count); - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(toIndex, Count); - ArgumentOutOfRangeException.ThrowIfNegative(count); - ArgumentOutOfRangeException.ThrowIfGreaterThan(fromIndex + count, Count, nameof(fromIndex)); - ArgumentOutOfRangeException.ThrowIfGreaterThan(toIndex + count, Count, nameof(toIndex)); + for (var i = start; i != end; i += direction) + { + entries[i] = entries[i + amount]; + UpdateBucketIndex(i + amount, -amount); + } - if (fromIndex == toIndex || count == 0) - { - return; - } + var buckets = _buckets; + // Copy entries to destination + for (var i = 0; i < count; ++i) + { + var temp = entriesToMove[i]; + AddEntryToBucket(ref temp, toIndex + i, buckets); + entries[toIndex + i] = temp; + } - var entries = _entries; - // Make a copy of the entries to move. Consider using ArrayPool instead to avoid allocations? - var entriesToMove = new Entry[count]; - for (var i = 0; i < count; ++i) - { - entriesToMove[i] = entries[fromIndex + i]; - RemoveEntryFromBucket(fromIndex + i); - } + ++_version; + } - // Move entries in between - var direction = 1; - var amount = count; - var start = fromIndex; - var end = toIndex; - if (fromIndex > toIndex) - { - direction = -1; - amount = -count; - start = fromIndex + count - 1; - end = toIndex + count - 1; - } - for (var i = start; i != end; i += direction) - { - entries[i] = entries[i + amount]; - UpdateBucketIndex(i + amount, -amount); - } + /// + /// Removes the value with the specified key from the as an O(n) operation. + /// + /// The key of the element to remove. + /// + /// true if the element is successfully found and removed; otherwise, false. This method returns false if is + /// not found in the . + /// + /// is null. + public bool Remove(TKey key) + => Remove(key, out _); - var buckets = _buckets; - // Copy entries to destination - for (var i = 0; i < count; ++i) - { - var temp = entriesToMove[i]; - AddEntryToBucket(ref temp, toIndex + i, buckets); - entries[toIndex + i] = temp; - } - ++_version; + /// + /// Removes the value with the specified key from the and returns the value as an O(n) + /// operation. + /// + /// The key of the element to remove. + /// + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the + /// default value for the type of the parameter. This parameter is passed uninitialized. + /// + /// + /// true if the element is successfully found and removed; otherwise, false. This method returns false if is + /// not found in the . + /// + /// is null. + public bool Remove(TKey key, out TValue value) + { + var index = IndexOf(key); + if (index >= 0) + { + value = _entries[index].Value; + RemoveAt(index); + return true; } - /// - /// Removes the value with the specified key from the as an O(n) operation. - /// - /// The key of the element to remove. - /// true if the element is successfully found and removed; otherwise, false. This method returns false if is not found in the . - /// is null. - public bool Remove(TKey key) => Remove(key, out _); + value = default!; + return false; + } - /// - /// Removes the value with the specified key from the and returns the value as an O(n) operation. - /// - /// The key of the element to remove. - /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - /// true if the element is successfully found and removed; otherwise, false. This method returns false if is not found in the . - /// is null. - public bool Remove(TKey key, out TValue value) + /// + /// Removes the value at the specified index from the as an O(n) operation. + /// + /// The zero-based index of the element to remove. + /// + /// is less than 0.-or- is equal to or greater + /// than . + /// + public void RemoveAt(int index) + { + var count = Count; + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, count); + + // Remove the entry from the bucket + RemoveEntryFromBucket(index); + + // Decrement the indices > index + var entries = _entries; + for (var i = index + 1; i < count; ++i) { - var index = IndexOf(key); - if (index >= 0) - { - value = _entries[index].Value; - RemoveAt(index); - return true; - } - value = default!; - return false; + entries[i - 1] = entries[i]; + UpdateBucketIndex(i, incrementAmount: -1); } - /// - /// Removes the value at the specified index from the as an O(n) operation. - /// - /// The zero-based index of the element to remove. - /// is less than 0.-or- is equal to or greater than . - public void RemoveAt(int index) - { - var count = Count; - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, count); + --_count; + entries[_count] = default; + ++_version; + } - // Remove the entry from the bucket - RemoveEntryFromBucket(index); + /// + /// Sets the capacity of an object to the actual number of elements it contains, rounded up + /// to a nearby, implementation-specific value. + /// + public void TrimExcess() + => TrimExcess(Count); - // Decrement the indices > index - var entries = _entries; - for (var i = index + 1; i < count; ++i) - { - entries[i - 1] = entries[i]; - UpdateBucketIndex(i, incrementAmount: -1); - } - --_count; - entries[_count] = default; + /// + /// Sets the capacity of an object to the specified capacity, rounded up to a nearby, + /// implementation-specific value. + /// + /// The number of elements that the must be able to contain. + /// + /// is less than + /// . + /// + public void TrimExcess(int capacity) + { + ArgumentOutOfRangeException.ThrowIfLessThan(capacity, Count); + + var newSize = HashHelpers.GetPrime(capacity); + if (newSize < _entries.Length) + { + Resize(newSize); ++_version; } + } - /// - /// Sets the capacity of an object to the actual number of elements it contains, rounded up to a nearby, implementation-specific value. - /// - public void TrimExcess() => TrimExcess(Count); + /// + /// Tries to add the specified key and value to the dictionary as an O(1) operation. + /// + /// The key of the element to add. + /// The value of the element to add. The value can be null for reference types. + /// + /// true if the element was added to the ; false if the + /// already contained an element with the specified key. + /// + /// is null. + public bool TryAdd(TKey key, TValue value) + => TryInsert(null, key, value, InsertionBehavior.None); - /// - /// Sets the capacity of an object to the specified capacity, rounded up to a nearby, implementation-specific value. - /// - /// The number of elements that the must be able to contain. - /// is less than . - public void TrimExcess(int capacity) + /// + /// Gets the value associated with the specified key as an O(1) operation. + /// + /// The key of the value to get. + /// + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the + /// default value for the type of the parameter. This parameter is passed uninitialized. + /// + /// true if the contains an element with the specified key; otherwise, false. + /// is null. + public bool TryGetValue(TKey key, out TValue value) + { + var index = IndexOf(key); + if (index >= 0) { - ArgumentOutOfRangeException.ThrowIfLessThan(capacity, Count); - - var newSize = HashHelpers.GetPrime(capacity); - if (newSize < _entries.Length) - { - Resize(newSize); - ++_version; - } + value = _entries[index].Value; + return true; } - /// - /// Tries to add the specified key and value to the dictionary as an O(1) operation. - /// - /// The key of the element to add. - /// The value of the element to add. The value can be null for reference types. - /// true if the element was added to the ; false if the already contained an element with the specified key. - /// is null. - public bool TryAdd(TKey key, TValue value) => TryInsert(null, key, value, InsertionBehavior.None); + value = default!; + return false; + } - /// - /// Gets the value associated with the specified key as an O(1) operation. - /// - /// The key of the value to get. - /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - /// true if the contains an element with the specified key; otherwise, false. - /// is null. - public bool TryGetValue(TKey key, out TValue value) + #region Explicit Interface Implementation + + KeyValuePair IList>.this[int index] + { + get { - var index = IndexOf(key); - if (index >= 0) - { - value = _entries[index].Value; - return true; - } - value = default!; - return false; - } + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); - #region Explicit Interface Implementation - KeyValuePair IList>.this[int index] + var entry = _entries[index]; + return new KeyValuePair(entry.Key, entry.Value); + } + set { - get - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); - var entry = _entries[index]; - return new KeyValuePair(entry.Key, entry.Value); - } - set + var key = value.Key; + var foundIndex = IndexOf(key, out var hashCode); + // key does not exist in dictionary thus replace entry at index + if (foundIndex < 0) { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); - - var key = value.Key; - var foundIndex = IndexOf(key, out var hashCode); - // key does not exist in dictionary thus replace entry at index - if (foundIndex < 0) + RemoveEntryFromBucket(index); + var entry = new Entry { - RemoveEntryFromBucket(index); - var entry = new Entry { HashCode = hashCode, Key = key, Value = value.Value }; - AddEntryToBucket(ref entry, index, _buckets); - _entries[index] = entry; - ++_version; - } - // key already exists in dictionary at the specified index thus just replace the key and value as hashCode remains the same - else if (foundIndex == index) - { - ref var entry = ref _entries[index]; - entry.Key = key; - entry.Value = value.Value; - } - // key already exists in dictionary but not at the specified index thus throw exception as this method shouldn't affect the indices of other entries - else - { - throw new ArgumentException($"Key {key} already exists in dictionary but not at the specified index {index}"); - } + HashCode = hashCode, + Key = key, + Value = value.Value + }; + AddEntryToBucket(ref entry, index, _buckets); + _entries[index] = entry; + ++_version; + } + // key already exists in dictionary at the specified index thus just replace the key and value as hashCode remains the same + else if (foundIndex == index) + { + ref var entry = ref _entries[index]; + entry.Key = key; + entry.Value = value.Value; + } + // key already exists in dictionary but not at the specified index thus throw exception as this method shouldn't affect the indices of other entries + else + { + throw new ArgumentException($"Key {key} already exists in dictionary but not at the specified index {index}"); } } + } - KeyValuePair IReadOnlyList>.this[int index] => ((IList>)this)[index]; + KeyValuePair IReadOnlyList>.this[int index] + => ((IList>)this)[index]; - ICollection IDictionary.Keys => Keys; + ICollection IDictionary.Keys + => Keys; - ICollection IDictionary.Values => Values; + ICollection IDictionary.Values + => Values; - IEnumerable IReadOnlyDictionary.Keys => Keys; + IEnumerable IReadOnlyDictionary.Keys + => Keys; - IEnumerable IReadOnlyDictionary.Values => Values; + IEnumerable IReadOnlyDictionary.Values + => Values; - bool ICollection>.IsReadOnly => false; + bool ICollection>.IsReadOnly + => false; - IEnumerator> IEnumerable>.GetEnumerator() => GetEnumerator(); + IEnumerator> IEnumerable>.GetEnumerator() + => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - void ICollection>.Add(KeyValuePair item) => Add(item.Key, item.Value); + void ICollection>.Add(KeyValuePair item) + => Add(item.Key, item.Value); - bool ICollection>.Contains(KeyValuePair item) => TryGetValue(item.Key, out var value) && EqualityComparer.Default.Equals(value, item.Value); + bool ICollection>.Contains(KeyValuePair item) + => TryGetValue(item.Key, out var value) && EqualityComparer.Default.Equals(value, item.Value); - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - ArgumentNullException.ThrowIfNull(array); - ArgumentOutOfRangeException.ThrowIfGreaterThan(arrayIndex, array.Length); - var count = Count; - ArgumentOutOfRangeException.ThrowIfLessThan(array.Length - arrayIndex, count); + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + ArgumentNullException.ThrowIfNull(array); + ArgumentOutOfRangeException.ThrowIfGreaterThan(arrayIndex, array.Length); + var count = Count; + ArgumentOutOfRangeException.ThrowIfLessThan(array.Length - arrayIndex, count); - var entries = _entries; - for (var i = 0; i < count; ++i) - { - var entry = entries[i]; - array[i + arrayIndex] = new KeyValuePair(entry.Key, entry.Value); - } + var entries = _entries; + for (var i = 0; i < count; ++i) + { + var entry = entries[i]; + array[i + arrayIndex] = new KeyValuePair(entry.Key, entry.Value); } + } - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) + { + var index = IndexOf(item.Key); + if (index >= 0 && EqualityComparer.Default.Equals(_entries[index].Value, item.Value)) { - var index = IndexOf(item.Key); - if (index >= 0 && EqualityComparer.Default.Equals(_entries[index].Value, item.Value)) - { - RemoveAt(index); - return true; - } - return false; + RemoveAt(index); + return true; } - int IList>.IndexOf(KeyValuePair item) + return false; + } + + int IList>.IndexOf(KeyValuePair item) + { + var index = IndexOf(item.Key); + if (index >= 0 && !EqualityComparer.Default.Equals(_entries[index].Value, item.Value)) { - var index = IndexOf(item.Key); - if (index >= 0 && !EqualityComparer.Default.Equals(_entries[index].Value, item.Value)) - { - index = -1; - } - return index; + index = -1; } - void IList>.Insert(int index, KeyValuePair item) => Insert(index, item.Key, item.Value); - #endregion + return index; + } - private Entry[] Resize(int newSize) - { - var newBuckets = new int[newSize]; - var newEntries = new Entry[newSize]; + void IList>.Insert(int index, KeyValuePair item) + => Insert(index, item.Key, item.Value); - var count = Count; - Array.Copy(_entries, newEntries, count); - for (var i = 0; i < count; ++i) - { - AddEntryToBucket(ref newEntries[i], i, newBuckets); - } + #endregion - _buckets = newBuckets; - _entries = newEntries; - return newEntries; - } + private Entry[] Resize(int newSize) + { + var newBuckets = new int[newSize]; + var newEntries = new Entry[newSize]; - private int IndexOf(TKey key, out uint hashCode) + var count = Count; + Array.Copy(_entries, newEntries, count); + for (var i = 0; i < count; ++i) { - ArgumentNullException.ThrowIfNull(key); - - var comparer = _comparer; - hashCode = (uint)(comparer?.GetHashCode(key) ?? key.GetHashCode()); - var index = _buckets[(int)(hashCode % (uint)_buckets.Length)] - 1; - if (index >= 0) - { - comparer ??= EqualityComparer.Default; - var entries = _entries; - var collisionCount = 0; - do - { - var entry = entries[index]; - if (entry.HashCode == hashCode && comparer.Equals(entry.Key, key)) - { - break; - } - index = entry.Next; - if (collisionCount >= entries.Length) - { - // The chain of entries forms a loop; which means a concurrent update has happened. - // Break out of the loop and throw, rather than looping forever. - throw new InvalidOperationException("Concurrent update detected"); - } - ++collisionCount; - } while (index >= 0); - } - return index; + AddEntryToBucket(ref newEntries[i], i, newBuckets); } - private bool TryInsert(int? index, TKey key, TValue value, InsertionBehavior behavior) + _buckets = newBuckets; + _entries = newEntries; + return newEntries; + } + + private int IndexOf(TKey key, out uint hashCode) + { + ArgumentNullException.ThrowIfNull(key); + + var comparer = _comparer; + hashCode = (uint)(comparer?.GetHashCode(key) ?? key.GetHashCode()); + var index = _buckets[(int)(hashCode % (uint)_buckets.Length)] - 1; + if (index >= 0) { - var i = IndexOf(key, out var hashCode); - if (i >= 0) + comparer ??= EqualityComparer.Default; + var entries = _entries; + var collisionCount = 0; + do { - switch (behavior) + var entry = entries[index]; + if (entry.HashCode == hashCode && comparer.Equals(entry.Key, key)) { - case InsertionBehavior.OverwriteExisting: - _entries[i].Value = value; - return true; - case InsertionBehavior.ThrowOnExisting: - throw new ArgumentException($"Key {key} is already present"); - default: - return false; + break; } - } - AddInternal(index, key, value, hashCode); - return true; + index = entry.Next; + if (collisionCount >= entries.Length) + { + // The chain of entries forms a loop; which means a concurrent update has happened. + // Break out of the loop and throw, rather than looping forever. + throw new InvalidOperationException("Concurrent update detected"); + } + + ++collisionCount; + } + while (index >= 0); } - private int AddInternal(int? index, TKey key, TValue value, uint hashCode) + return index; + } + + private bool TryInsert(int? index, TKey key, TValue value, InsertionBehavior behavior) + { + var i = IndexOf(key, out var hashCode); + if (i >= 0) { - var entries = _entries; - // Check if resize is needed - var count = Count; - if (entries.Length == count || entries.Length == 1) + switch (behavior) { - entries = Resize(HashHelpers.ExpandPrime(entries.Length)); + case InsertionBehavior.OverwriteExisting: + _entries[i].Value = value; + return true; + case InsertionBehavior.ThrowOnExisting: + throw new ArgumentException($"Key {key} is already present"); + default: + return false; } + } - // Increment indices >= index; - var actualIndex = index ?? count; - for (var i = count - 1; i >= actualIndex; --i) - { - entries[i + 1] = entries[i]; - UpdateBucketIndex(i, incrementAmount: 1); - } + AddInternal(index, key, value, hashCode); + return true; + } - ref var entry = ref entries[actualIndex]; - entry.HashCode = hashCode; - entry.Key = key; - entry.Value = value; - AddEntryToBucket(ref entry, actualIndex, _buckets); - ++_count; - ++_version; - return actualIndex; + private int AddInternal(int? index, TKey key, TValue value, uint hashCode) + { + var entries = _entries; + // Check if resize is needed + var count = Count; + if (entries.Length == count || entries.Length == 1) + { + entries = Resize(HashHelpers.ExpandPrime(entries.Length)); } - // Returns the index of the next entry in the bucket - private void AddEntryToBucket(ref Entry entry, int entryIndex, int[] buckets) + // Increment indices >= index; + var actualIndex = index ?? count; + for (var i = count - 1; i >= actualIndex; --i) { - ref var b = ref buckets[(int)(entry.HashCode % (uint)buckets.Length)]; - entry.Next = b - 1; - b = entryIndex + 1; + entries[i + 1] = entries[i]; + UpdateBucketIndex(i, incrementAmount: 1); } - private void RemoveEntryFromBucket(int entryIndex) + ref var entry = ref entries[actualIndex]; + entry.HashCode = hashCode; + entry.Key = key; + entry.Value = value; + AddEntryToBucket(ref entry, actualIndex, _buckets); + ++_count; + ++_version; + return actualIndex; + } + + // Returns the index of the next entry in the bucket + private void AddEntryToBucket(ref Entry entry, int entryIndex, int[] buckets) + { + ref var b = ref buckets[(int)(entry.HashCode % (uint)buckets.Length)]; + entry.Next = b - 1; + b = entryIndex + 1; + } + + private void RemoveEntryFromBucket(int entryIndex) + { + var entries = _entries; + var entry = entries[entryIndex]; + ref var b = ref _buckets[(int)(entry.HashCode % (uint)_buckets.Length)]; + // Bucket was pointing to removed entry. Update it to point to the next in the chain + if (b == entryIndex + 1) { - var entries = _entries; - var entry = entries[entryIndex]; - ref var b = ref _buckets[(int)(entry.HashCode % (uint)_buckets.Length)]; - // Bucket was pointing to removed entry. Update it to point to the next in the chain - if (b == entryIndex + 1) - { - b = entry.Next + 1; - } - else + b = entry.Next + 1; + } + else + { + // Start at the entry the bucket points to, and walk the chain until we find the entry with the index we want to remove, then fix the chain + var i = b - 1; + var collisionCount = 0; + while (true) { - // Start at the entry the bucket points to, and walk the chain until we find the entry with the index we want to remove, then fix the chain - var i = b - 1; - var collisionCount = 0; - while (true) + ref var e = ref entries[i]; + if (e.Next == entryIndex) { - ref var e = ref entries[i]; - if (e.Next == entryIndex) - { - e.Next = entry.Next; - return; - } - i = e.Next; - if (collisionCount >= entries.Length) - { - // The chain of entries forms a loop; which means a concurrent update has happened. - // Break out of the loop and throw, rather than looping forever. - throw new InvalidOperationException("Concurrent update detected"); - } - ++collisionCount; + e.Next = entry.Next; + return; } + + i = e.Next; + if (collisionCount >= entries.Length) + { + // The chain of entries forms a loop; which means a concurrent update has happened. + // Break out of the loop and throw, rather than looping forever. + throw new InvalidOperationException("Concurrent update detected"); + } + + ++collisionCount; } } + } - private void UpdateBucketIndex(int entryIndex, int incrementAmount) + private void UpdateBucketIndex(int entryIndex, int incrementAmount) + { + var entries = _entries; + var entry = entries[entryIndex]; + ref var b = ref _buckets[(int)(entry.HashCode % (uint)_buckets.Length)]; + // Bucket was pointing to entry. Increment the index by incrementAmount. + if (b == entryIndex + 1) { - var entries = _entries; - var entry = entries[entryIndex]; - ref var b = ref _buckets[(int)(entry.HashCode % (uint)_buckets.Length)]; - // Bucket was pointing to entry. Increment the index by incrementAmount. - if (b == entryIndex + 1) - { - b += incrementAmount; - } - else + b += incrementAmount; + } + else + { + // Start at the entry the bucket points to, and walk the chain until we find the entry with the index we want to increment. + var i = b - 1; + var collisionCount = 0; + while (true) { - // Start at the entry the bucket points to, and walk the chain until we find the entry with the index we want to increment. - var i = b - 1; - var collisionCount = 0; - while (true) + ref var e = ref entries[i]; + if (e.Next == entryIndex) { - ref var e = ref entries[i]; - if (e.Next == entryIndex) - { - e.Next += incrementAmount; - return; - } - i = e.Next; - if (collisionCount >= entries.Length) - { - // The chain of entries forms a loop; which means a concurrent update has happened. - // Break out of the loop and throw, rather than looping forever. - throw new InvalidOperationException("Concurrent update detected"); - } - ++collisionCount; + e.Next += incrementAmount; + return; } + + i = e.Next; + if (collisionCount >= entries.Length) + { + // The chain of entries forms a loop; which means a concurrent update has happened. + // Break out of the loop and throw, rather than looping forever. + throw new InvalidOperationException("Concurrent update detected"); + } + + ++collisionCount; } } + } + + /// + /// Enumerates the elements of a . + /// + public struct Enumerator : IEnumerator> + { + private readonly OrderedDictionary _orderedDictionary; + private readonly int _version; + private int _index; + private KeyValuePair _current; /// - /// Enumerates the elements of a . + /// Gets the element at the current position of the enumerator. /// - public struct Enumerator : IEnumerator> - { - private readonly OrderedDictionary _orderedDictionary; - private readonly int _version; - private int _index; - private KeyValuePair _current; + /// The element in the at the current position of the enumerator. + public KeyValuePair Current + => _current; - /// - /// Gets the element at the current position of the enumerator. - /// - /// The element in the at the current position of the enumerator. - public KeyValuePair Current => _current; + object IEnumerator.Current + => _current; - object IEnumerator.Current => _current; + internal Enumerator(OrderedDictionary orderedDictionary) + { + _orderedDictionary = orderedDictionary; + _version = orderedDictionary._version; + _index = 0; + } - internal Enumerator(OrderedDictionary orderedDictionary) - { - _orderedDictionary = orderedDictionary; - _version = orderedDictionary._version; - _index = 0; - } + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + } - /// - /// Releases all resources used by the . - /// - public void Dispose() + /// + /// Advances the enumerator to the next element of the . + /// + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the + /// collection. + /// + /// The collection was modified after the enumerator was created. + public bool MoveNext() + { + if (_version != _orderedDictionary._version) { + throw new InvalidOperationException("The dictionary has been modified during enumeration"); } - /// - /// Advances the enumerator to the next element of the . - /// - /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. - /// The collection was modified after the enumerator was created. - public bool MoveNext() + if (_index < _orderedDictionary.Count) { - if (_version != _orderedDictionary._version) - { - throw new InvalidOperationException("The dictionary has been modified during enumeration"); - } - - if (_index < _orderedDictionary.Count) - { - var entry = _orderedDictionary._entries[_index]; - _current = new KeyValuePair(entry.Key, entry.Value); - ++_index; - return true; - } - _current = default; - return false; + var entry = _orderedDictionary._entries[_index]; + _current = new KeyValuePair(entry.Key, entry.Value); + ++_index; + return true; } - void IEnumerator.Reset() - { - if (_version != _orderedDictionary._version) - { - throw new InvalidOperationException("The dictionary has been modified during enumeration"); - } - - _index = 0; - _current = default; - } + _current = default; + return false; } - private enum InsertionBehavior + void IEnumerator.Reset() { - None = 0, - OverwriteExisting = 1, - ThrowOnExisting = 2 + if (_version != _orderedDictionary._version) + { + throw new InvalidOperationException("The dictionary has been modified during enumeration"); + } + + _index = 0; + _current = default; } } + + private enum InsertionBehavior + { + None = 0, + OverwriteExisting = 1, + ThrowOnExisting = 2 + } } diff --git a/src/Shared/SharedStopwatch.cs b/src/Shared/SharedStopwatch.cs index 1c012199710..a96bc25d146 100644 --- a/src/Shared/SharedStopwatch.cs +++ b/src/Shared/SharedStopwatch.cs @@ -8,15 +8,11 @@ internal readonly struct SharedStopwatch { private static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); - private readonly TimeSpan _started; - private SharedStopwatch(TimeSpan started) - { - _started = started; - } + => Elapsed = started; public TimeSpan Elapsed - => Stopwatch.Elapsed - _started; + => Stopwatch.Elapsed - field; public static SharedStopwatch StartNew() { diff --git a/src/Shared/SharedTypeExtensions.cs b/src/Shared/SharedTypeExtensions.cs index 3e87ab98dc6..41d1d826d58 100644 --- a/src/Shared/SharedTypeExtensions.cs +++ b/src/Shared/SharedTypeExtensions.cs @@ -63,9 +63,8 @@ public static bool IsPropertyBagType([DynamicallyAccessedMembers(DynamicallyAcce } var types = GetGenericTypeImplementations(type, typeof(IDictionary<,>)); - return types.Any( - t => t.GetGenericArguments()[0] == typeof(string) - && t.GetGenericArguments()[1] == typeof(object)); + return types.Any(t => t.GetGenericArguments()[0] == typeof(string) + && t.GetGenericArguments()[1] == typeof(object)); } public static Type MakeNullable(this Type type, bool nullable = true) @@ -314,9 +313,8 @@ static IEnumerable GetInterfacesSuppressed(Type type) types ??= []; return type.GetTypeInfo().DeclaredConstructors - .SingleOrDefault( - c => !c.IsStatic - && c.GetParameters().Select(p => p.ParameterType).SequenceEqual(types))!; + .SingleOrDefault(c => !c.IsStatic + && c.GetParameters().Select(p => p.ParameterType).SequenceEqual(types))!; } public static IEnumerable GetPropertiesInHierarchy(this Type type, string name) @@ -383,15 +381,14 @@ public static MethodInfo GetGenericMethod( Func parameterGenerator, bool? @override = null) => type.GetMethods(bindingFlags) - .Single( - mi => mi.Name == name - && ((genericParameterCount == 0 && !mi.IsGenericMethod) - || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) - && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( - parameterGenerator( - type.IsGenericType ? type.GetGenericArguments() : Array.Empty(), - mi.IsGenericMethod ? mi.GetGenericArguments() : Array.Empty())) - && (!@override.HasValue || (@override.Value == (mi.GetBaseDefinition().DeclaringType != mi.DeclaringType)))); + .Single(mi => mi.Name == name + && ((genericParameterCount == 0 && !mi.IsGenericMethod) + || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) + && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( + parameterGenerator( + type.IsGenericType ? type.GetGenericArguments() : [], + mi.IsGenericMethod ? mi.GetGenericArguments() : [])) + && (!@override.HasValue || (@override.Value == (mi.GetBaseDefinition().DeclaringType != mi.DeclaringType)))); private static readonly Dictionary CommonTypeDictionary = new() { @@ -426,13 +423,14 @@ public static ConstantExpression GetDefaultValueConstant(this Type type) [RequiresUnreferencedCode("Gets all types from the given assembly - unsafe for trimming")] public static IEnumerable GetConstructibleTypes( - this Assembly assembly, IDiagnosticsLogger? logger = null) - => assembly.GetLoadableDefinedTypes(logger).Where( - t => t is { IsAbstract: false, IsGenericTypeDefinition: false }); + this Assembly assembly, + IDiagnosticsLogger? logger = null) + => assembly.GetLoadableDefinedTypes(logger).Where(t => t is { IsAbstract: false, IsGenericTypeDefinition: false }); [RequiresUnreferencedCode("Gets all types from the given assembly - unsafe for trimming")] public static IEnumerable GetLoadableDefinedTypes( - this Assembly assembly, IDiagnosticsLogger? logger = null) + this Assembly assembly, + IDiagnosticsLogger? logger = null) { try {