diff --git a/src/Components/Components/src/ParameterView.cs b/src/Components/Components/src/ParameterView.cs index fb7329aab2..7ecbade21e 100644 --- a/src/Components/Components/src/ParameterView.cs +++ b/src/Components/Components/src/ParameterView.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Components.Reflection; +using Microsoft.AspNetCore.Components.Rendering; using Microsoft.AspNetCore.Components.RenderTree; namespace Microsoft.AspNetCore.Components @@ -20,19 +21,24 @@ namespace Microsoft.AspNetCore.Components RenderTreeFrame.Element(0, string.Empty).WithComponentSubtreeLength(1) }; - private static readonly ParameterView _empty = new ParameterView(_emptyFrames, 0, null); + private static readonly ParameterView _empty = new ParameterView(null, _emptyFrames, 0, null); + + // If a value is provided for this field, then the ParameterView instance is only + // valid for as long as the lifetime owner says it is + private readonly RenderBatchBuilder _lifetimeOwner; private readonly RenderTreeFrame[] _frames; private readonly int _ownerIndex; private readonly IReadOnlyList _cascadingParametersOrNull; - internal ParameterView(RenderTreeFrame[] frames, int ownerIndex) - : this(frames, ownerIndex, null) + internal ParameterView(RenderBatchBuilder lifetimeOwnerOrNull, RenderTreeFrame[] frames, int ownerIndex) + : this(lifetimeOwnerOrNull, frames, ownerIndex, null) { } - private ParameterView(RenderTreeFrame[] frames, int ownerIndex, IReadOnlyList cascadingParametersOrNull) + private ParameterView(RenderBatchBuilder lifetimeOwnerOrNull, RenderTreeFrame[] frames, int ownerIndex, IReadOnlyList cascadingParametersOrNull) { + _lifetimeOwner = lifetimeOwnerOrNull; _frames = frames; _ownerIndex = ownerIndex; _cascadingParametersOrNull = cascadingParametersOrNull; @@ -108,7 +114,7 @@ namespace Microsoft.AspNetCore.Components } internal ParameterView WithCascadingParameters(IReadOnlyList cascadingParameters) - => new ParameterView(_frames, _ownerIndex, cascadingParameters); + => new ParameterView(_lifetimeOwner, _frames, _ownerIndex, cascadingParameters); // It's internal because there isn't a known use case for user code comparing // ParameterView instances, and even if there was, it's unlikely it should @@ -215,7 +221,7 @@ namespace Microsoft.AspNetCore.Components frames[++i] = RenderTreeFrame.Attribute(i, kvp.Key, kvp.Value); } - return new ParameterView(frames, 0); + return new ParameterView(null, frames, 0); } /// diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs index bc6f82df29..ee40692430 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs @@ -364,8 +364,8 @@ namespace Microsoft.AspNetCore.Components.RenderTree // Handles the diff for attribute nodes only - this invariant is enforced by the caller. // // The diff for attributes is different because we allow attributes to appear in any order. - // Put another way, the attributes list of an element or component is *conceptually* - // unordered. This is a case where we can produce a more minimal diff by avoiding + // Put another way, the attributes list of an element or component is *conceptually* + // unordered. This is a case where we can produce a more minimal diff by avoiding // non-meaningful reorderings of attributes. private static void AppendAttributeDiffEntriesForRange( ref DiffContext diffContext, @@ -519,8 +519,8 @@ namespace Microsoft.AspNetCore.Components.RenderTree // comparisons it wants with the old values. Later we could choose to pass the // old parameter values if we wanted. By default, components always rerender // after any SetParameters call, which is safe but now always optimal for perf. - var oldParameters = new ParameterView(oldTree, oldComponentIndex); - var newParameters = new ParameterView(newTree, newComponentIndex); + var oldParameters = new ParameterView(null, oldTree, oldComponentIndex); + var newParameters = new ParameterView(diffContext.BatchBuilder, newTree, newComponentIndex); if (!newParameters.DefinitelyEquals(oldParameters)) { componentState.SetDirectParameters(newParameters); @@ -893,7 +893,7 @@ namespace Microsoft.AspNetCore.Components.RenderTree var childComponentState = frame.ComponentState; // Set initial parameters - var initialParameters = new ParameterView(frames, frameIndex); + var initialParameters = new ParameterView(diffContext.BatchBuilder, frames, frameIndex); childComponentState.SetDirectParameters(initialParameters); } @@ -957,7 +957,7 @@ namespace Microsoft.AspNetCore.Components.RenderTree /// Exists only so that the various methods in this class can call each other without /// constantly building up long lists of parameters. Is private to this class, so the /// fact that it's a mutable struct is manageable. - /// + /// /// Always pass by ref to avoid copying, and because the 'SiblingIndex' is mutable. /// private struct DiffContext diff --git a/src/Components/Components/src/Rendering/ComponentState.cs b/src/Components/Components/src/Rendering/ComponentState.cs index 8394a2adba..e94ddc370d 100644 --- a/src/Components/Components/src/Rendering/ComponentState.cs +++ b/src/Components/Components/src/Rendering/ComponentState.cs @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Components.Rendering public void NotifyCascadingValueChanged() { var directParams = _latestDirectParametersSnapshot != null - ? new ParameterView(_latestDirectParametersSnapshot.Buffer, 0) + ? new ParameterView(null, _latestDirectParametersSnapshot.Buffer, 0) : ParameterView.Empty; var allParams = directParams.WithCascadingParameters(_cascadingParameters); var task = Component.SetParametersAsync(allParams); diff --git a/src/Components/Components/test/ParameterViewTest.Assignment.cs b/src/Components/Components/test/ParameterViewTest.Assignment.cs index 9f677ef50a..f5d0d7a257 100644 --- a/src/Components/Components/test/ParameterViewTest.Assignment.cs +++ b/src/Components/Components/test/ParameterViewTest.Assignment.cs @@ -673,7 +673,7 @@ namespace Microsoft.AspNetCore.Components } builder.CloseComponent(); - var view = new ParameterView(builder.GetFrames().Array, ownerIndex: 0); + var view = new ParameterView(null, builder.GetFrames().Array, ownerIndex: 0); var cascadingParameters = new List(); foreach (var kvp in _keyValuePairs) diff --git a/src/Components/Components/test/ParameterViewTest.cs b/src/Components/Components/test/ParameterViewTest.cs index cfb3191ca5..96072a2dad 100644 --- a/src/Components/Components/test/ParameterViewTest.cs +++ b/src/Components/Components/test/ParameterViewTest.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Components { RenderTreeFrame.ChildComponent(0, typeof(FakeComponent)).WithComponentSubtreeLength(1) }; - var parameters = new ParameterView(frames, 0); + var parameters = new ParameterView(null, frames, 0); // Assert Assert.Empty(ToEnumerable(parameters)); @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Components { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(1) }; - var parameters = new ParameterView(frames, 0); + var parameters = new ParameterView(null, frames, 0); // Assert Assert.Empty(ToEnumerable(parameters)); @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Components // end of the owner's descendants RenderTreeFrame.Attribute(3, "orphaned attribute", "value") }; - var parameters = new ParameterView(frames, 0); + var parameters = new ParameterView(null, frames, 0); // Assert Assert.Collection(ToEnumerable(parameters), @@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Components RenderTreeFrame.Element(3, "child element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(4, "child attribute", "some value") }; - var parameters = new ParameterView(frames, 0); + var parameters = new ParameterView(null, frames, 0); // Assert Assert.Collection(ToEnumerable(parameters), @@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Components var attribute1Value = new object(); var attribute2Value = new object(); var attribute3Value = new object(); - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value) @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Components public void CanTryGetNonExistingValue() { // Arrange - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "some other entry", new object()) @@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Components public void CanTryGetExistingValueWithCorrectType() { // Arrange - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "my entry", "hello") @@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var myEntryValue = new object(); - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "my entry", myEntryValue), @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var myEntryValue = new object(); - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), RenderTreeFrame.Attribute(1, "my entry", myEntryValue), @@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Components public void CanGetValueOrDefault_WithNonExistingValue() { // Arrange - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "some other entry", new object()) @@ -209,7 +209,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var explicitDefaultValue = new DateTime(2018, 3, 20); - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "some other entry", new object()) @@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.Components public void ThrowsIfTryGetExistingValueWithIncorrectType() { // Arrange - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "my entry", "hello") @@ -275,7 +275,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var entry2Value = new object(); - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), RenderTreeFrame.Attribute(0, "entry 1", "value 1"), @@ -304,7 +304,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var myEntryValue = new object(); - var parameters = new ParameterView(new[] + var parameters = new ParameterView(null, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "unrelated value", new object())