Fix NullReferenceException when using x:Name on resources#32897
Fix NullReferenceException when using x:Name on resources#32897jfversluis merged 1 commit intoinflight/currentfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a NullReferenceException that occurred when using x:Name on brush resources (like SolidColorBrush) in XAML. The issue happened because GetHashCode() was called during NameScope registration before properties were initialized.
Key Changes
- Added null-safe operators to
GetHashCode()implementations across brush types - Modernized hash code generation using
HashCode.Combine()for non-NETSTANDARD targets - Added comprehensive XAML unit test to verify the fix across all inflators
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/Controls/tests/Xaml.UnitTests/Issues/Maui28711.xaml | Test XAML file that reproduces the issue with x:Name on SolidColorBrush in Resources |
| src/Controls/tests/Xaml.UnitTests/Issues/Maui28711.xaml.cs | Unit test verifying the page loads without crashing and the named brush is properly accessible |
| src/Controls/src/Core/SolidColorBrush.cs | Fixed GetHashCode() to handle null Color property and use modern hash code generation |
| src/Controls/src/Core/ImageBrush.cs | Updated GetHashCode() to use modern hash code generation (already had null-safety) |
| src/Controls/src/Core/GradientStop.cs | Updated GetHashCode() to use modern hash code generation (already had null-safety) |
| return unchecked((int)(374761393U + 3266489917U * (uint)(Color?.GetHashCode() ?? 0))); | ||
| #else | ||
| return HashCode.Combine(Color); |
There was a problem hiding this comment.
The GetHashCode() implementation only includes Color but the Equals() method compares both Color and Offset. According to the C# equality contract, objects that are equal must have the same hash code. This violates the hash code contract because two GradientStop objects with the same color but different offsets would have the same hash code but would not be equal.
The implementation should include both properties:
#if NETSTANDARD
return unchecked((int)(374761393U + 3266489917U * (uint)(Color?.GetHashCode() ?? 0) + 1579312759U * (uint)Offset.GetHashCode()));
#else
return HashCode.Combine(Color, Offset);
#endif| return unchecked((int)(374761393U + 3266489917U * (uint)(Color?.GetHashCode() ?? 0))); | |
| #else | |
| return HashCode.Combine(Color); | |
| return unchecked((int)(374761393U + 3266489917U * (uint)(Color?.GetHashCode() ?? 0) + 1579312759U * (uint)Offset.GetHashCode())); | |
| #else | |
| return HashCode.Combine(Color, Offset); |
85d5961 to
79d0c2e
Compare
|
those mutable types shouldn't override GetHashCode or Equals to start with |
Fixes #28711 When using x:Name on a SolidColorBrush in ContentPage.Resources, a NullReferenceException was thrown because GetHashCode was called (during NameScope registration) before Color was set. The fix uses base.GetHashCode() (identity-based) instead of hashing the mutable Color/ImageSource properties. This is correct because: 1. These are mutable reference types - their hash shouldn't change 2. The original implementation was incorrect anyway (hash based on mutable state breaks dictionary/hashset semantics) Changes: - SolidColorBrush.GetHashCode(): Use base.GetHashCode() - GradientStop.GetHashCode(): Use base.GetHashCode() - ImageBrush.GetHashCode(): Use base.GetHashCode() - Add XAML unit test for x:Name on resources Close #28805
79d0c2e to
9026a6c
Compare
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Description
Fixes #28711
Close #28805
When using
x:Nameon aSolidColorBrush(or other brush types) inContentPage.Resources, aNullReferenceExceptionwas thrown. This occurred becauseGetHashCode()was called during NameScope registration before theColorproperty was set.Root Cause
When XAML elements with
x:Nameare registered in the NameScope, the registration callsGetHashCode()on the object (for dictionary storage). The originalSolidColorBrush.GetHashCode()implementation directly calledColor.GetHashCode()without null-checking, causing a crash whenColorwas stillnull.Changes
SolidColorBrush.GetHashCode(): Added null-safe operator (Color?.GetHashCode() ?? 0) and useHashCode.Combine()for proper hashingGradientStop.GetHashCode(): Updated to useHashCode.Combine()for proper hashing (fixes same potential issue)ImageBrush.GetHashCode(): Updated to useHashCode.Combine()for proper hashing (fixes same potential issue)The changes use
HashCode.Combine()for non-NETSTANDARD targets and a properly implemented hash formula for NETSTANDARD compatibility.Test
Added XAML unit test
Maui28711.xaml/.xaml.csthat:x:Name="namedBrush"on aSolidColorBrushin ResourcesComparison with PR #28805
This PR supersedes #28805 with the following improvements:
Xaml.UnitTestswithXamlInflatorparameter (as requested by reviewer @StephaneDelcroix)uncheckedto the NETSTANDARD path to properly handle potential overflow