-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
[controls] Brush.Foo should return immutable instances #3824
Conversation
@jonathanpeppers is there any value here with storing these on access into a local Dictionary or variable so they don't get allocated on every call? I realize there's the issue of the mutability but in theory we could account for that by subclassing the brush and throwing if you try to change the color. Just thinking if we can get best of both worlds |
@PureWeen we could subclass and make the But you could still do: Brush.Blue.SetValue(SolidColorBrush.ColorProperty, Color.Red); Is there a way to "extend" a WPF calls I don't there there is a concept of "freeze" in MAUI? |
@jonathanpeppers we have readonly keys you can use
My initial "semi-ok" approach here would be to do it via an OnPropertyChanged handler on the bindable property. Have that call into the concrete implementation and then you could override that to throw on the |
src/Controls/src/Core/Brush.cs
Outdated
public static SolidColorBrush Ivory => new(Colors.Ivory); | ||
public static SolidColorBrush Khaki => new(Colors.Ivory); |
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.
If I see typos like this, it's probably not on purpose?
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 found 3 like this after adding a test to check for it.
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.
yea, definitely not on purpose but it's been like that since XF :-/
So probably been wrong for a bit now
6b30bf4
to
7424327
Compare
When profiling a `dotnet new maui` app, with this package: https://github.com/jonathanpeppers/Mono.Profiler.Android The `alloc` report shows: Allocation summary Bytes Count Average Type name 39984 147 2 72 Microsoft.Maui.Controls.SolidColorBrush Stack trace: 38352 bytes from: (wrapper runtime-invoke) object:runtime_invoke_void (object,intptr,intptr,intptr) Microsoft.Maui.Controls.VisualElement:.cctor () (wrapper runtime-invoke) object:runtime_invoke_void (object,intptr,intptr,intptr) Microsoft.Maui.Controls.Brush:.cctor () Reviewing the `Brush` class, there are indeed 147 `SolidColorBrush` created on startup that are stored in fields. But what is weird about this, is that `SolidColorBrush` is mutable! public Color Color { get => (Color)GetValue(ColorProperty); set => SetValue(ColorProperty, value); } So I could literally write code like: Brush.Blue.Color = Colors.Red; Blue is red! (insert evil laughter?) I think the appropriate fix here is that all of these `static readonly` fields should just be properties that return a new `ImmutableBrush`. We can cache the values in fields on demand. Then someone can't do something evil like change `Blue` to `Red`? I reviewed WPF source code to check what they do, and they took a similar approach: https://github.com/dotnet/wpf/blob/5e8187344b2b561ef08b9ca2735cd89cbdd3c11e/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/brushes.cs#L33-L1586 We should make this API change now before MAUI is stable, and we have the side benefit to save 39984 bytes of memory on startup? I added tests for these scenarios, and discovered 3 typos for `Brush` colors that listed the wrong color.
7424327
to
f93b21a
Compare
Description of Change
When profiling a
dotnet new maui
app, with this package:https://github.com/jonathanpeppers/Mono.Profiler.Android
The
alloc
report shows:Stack trace:
Reviewing the
Brush
class, there are indeed 147SolidColorBrush
created on startup that are stored in fields.
But what is weird about this, is that
SolidColorBrush
is mutable!So I could literally write code like:
Blue is red! (insert evil laughter?)
I think the appropriate fix here is that all of these
static readonly
fields should just be properties that return a newImmutableBrush
. We can cache the values in fields on demand. Thensomeone can't do something evil like change
Blue
toRed
?I reviewed WPF source code to check what they do, and they took a
similar approach:
https://github.com/dotnet/wpf/blob/5e8187344b2b561ef08b9ca2735cd89cbdd3c11e/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/brushes.cs#L33-L1586
We should make this API change now before MAUI is stable, and we have
the side benefit to save 39984 bytes of memory on startup?
I added tests for these scenarios, and discovered 3 typos for
Brush
colors that listed the wrong color.
Additions made
static readonly
fields inBrush
are now properties that return a new instance.PR Checklist
Does this PR touch anything that might affect accessibility?
No