-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ParameterState: Func Comparer, implicit operator support #8629
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #8629 +/- ##
==========================================
+ Coverage 89.82% 90.03% +0.20%
==========================================
Files 412 418 +6
Lines 11878 12027 +149
Branches 2364 2372 +8
==========================================
+ Hits 10670 10828 +158
+ Misses 681 666 -15
- Partials 527 533 +6 ☔ View full report in Codecov by Sentry. |
One disadvantage is that current |
@henon Should I split the |
What about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the builder very much. What if we completely switch to the builder and remove the old register overloads?
With the naming I proposed it would be: var someParameter = RegisterParameterBuilder<double>(nameof(DoubleParam))
.WithParameterFunc(() => DoubleParam)
.WithEventCallbackFunc(() => DoubleParamChanged)
.WithChangeHandler(OnDoubleParamChanged)
.WithComparer(() => DoubleEqualityComparer); I think in this case we can even drop the var someParameter = RegisterParameterBuilder<double>(nameof(DoubleParam))
.WithParameter(() => DoubleParam)
.WithEventCallback(() => DoubleParamChanged)
.WithChangeHandler(OnDoubleParamChanged)
.WithComparer(() => DoubleEqualityComparer); |
Thanks for the feedback, will do the changes later. |
I agree. One way to deal with this would be to change to this kind of API (I know it sucks to make such changes now after having just refactored everything): Before: RegisterParameterBuilder<int>(nameof(Spacing))
.WithParameter(() => Spacing)
.WithChangeHandler(() => _childrenNeedUpdates = true)
.Attach(); After (no need to attach, and no need to have RegisterParameter<int>(nameof(Spacing)), builder => builder
.WithParameter(() => Spacing)
.WithChangeHandler(() => _childrenNeedUpdates = true)
); |
Eh, I think I don't like this construction and I would just recommend for non MudBlazor developers to use this: ParameterState<double> _ = RegisterParameterBuilder<double>(nameof(DoubleParam))
.WithParameter(() => DoubleParam)
.WithChangeHandler(ParameterChangedHandler)
.WithComparer(() => DoubleEqualityComparer); to avoid any kind of problems |
By the way, why is the |
MudBlazor/src/MudBlazor/State/Builder/RegisterParameterBuilderOfT.cs Lines 176 to 191 in d16001e
Because it glues everything together and pokes IParameterSetRegister
that will trigger this:
to add the state to the When you are using field it just getting triggered by the implicit cast automatically:
|
I see. Couldn't the ComponentBase keep track of all registered ParameterStateInternal and call Attach on all unattached i.e. in OnInitialized ? |
That's the thing, if |
I guess it depends on the point of view whether or not it's worth it. You don't have to document this case, you don't have to remember not to forget to call Attach and you don't have to debug and find the bug when you forgot to call Attach. Finally, we don't have to answer any issues of people who forgot to call Attach. Another possibility would be to throw an exception with a good message, if unattached builders are collected by the GC. |
This Attach problem arises due to the splitting of the ParameterState into the public variant and the internal variant. If you wouldn't split them and just have one ParameterState with internal API for the builder to configure it you wouldn't even need to attach because you have a parameter state object with a parameter name even before the builder starts adding the rest of the data and you could immediately store it in the parameter set. So this would be a third option. You'd have to remove |
Hehe, I like the name SmartAttachable |
Pushed code that shows how the track can be keeped. If you are happy with the design, I can add xml documents.
Can you explain this better, preferably with some pseudocode. |
Never mind, the autoattach you just implemented solves the problem just nicely. |
Yes, then we should merge this ASAP before it gets unnecessarily conflicted. |
Excellent job @ScarletKuro, I can't wait to leverage the implicit cast ! |
For future I still plan to rethink all this registration. using(var register = RegisterParameters())
{
variable1 = ... register.WithName(...) etc
variable2 = ... register.WithName(...) etc
} With using I want that when the scope is ended it would only then register everything to |
Another idea to consider: Add a public class MudComponentBase : ComponentBase {
public MudComponentBase() {
InitParameters();
}
private InitParameters() {
InitState();
FreezeState();
}
protected virtual InitState() { /*to be overridden*/ }
} |
Description
IParamterState
removalAs we agreed with @henon we drop the
IParamterState
, the existingParameterState
was renamed toParameterStateInternal
, and newParameterState
class was created that has the same definition asIParamterState
.This was necessary because implicit/explicit operators do not support in or out interfaces.
A support to convert
ParameterState
->T
was added.A new
RegisterParameterBuilder
builder was added.Do not confuse with the existing
ParameterAttachBuilder
. They work differently under the hood so we do need to keep theParameterAttachBuilder
too. TheRegisterParameterBuilder
was created specifically forMudComponentBase
so that you could also use the builder, instead of the overloads, the problem is that with the new Func Comparer (described below) and the static Comparer it would create 5 new overloads which is not desired and hard to maintain.Code example:
You do not need to call
.Attach()
method since it also supports implicit operator that will do the job for you.For now I left the
RegisterParameter
for backward compatibility as legacy, we might cleanup it when we decide to make this public.Support for
Func<IEqualityComparer<T>>
The initial problem was described here: #8416 (comment)
The problem is that sometimes the parameter has an associated comparer that is also marked as Blazor's
[Parameter]
and it could be changed at any time. A good example is theMudTreeView
component. The old arhitecture allowed only a "static" comparer that do not change duringParamterState
lifetime.Notice this special case:
MudBlazor/src/MudBlazor/State/ParameterStateInternalOfT.cs
Lines 130 to 139 in a84fe3c
As described in the code, we need it when the parameter and the associated comparer change at same time.
I noticed this a problem when I called in bUnit:
To understand it better here is the picture how it looks in the debug mode:
To support this we had to add the
CallerArgumentExpression
to theWithComparer
and new ruleComparerParameterLambdaExclusion
to extract the name from lambda.Without this special case the
SwapComparerAtSameTimeIntegrationTest
andSetParametersAsync_FuncCustomComparerAsParameter_Swap
tests would fail!NB! To use this
Func<IEqualityComparer<T>>
you do need to use theRegisterParameterBuilder
that has the associatedWithComparer
How Has This Been Tested?
New NUnit + bUnit tests, current tests.
Types of changes
Checklist
dev
).