-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Match component properties as case insensitive #10657
Conversation
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.
The change itself looks good. However, just to be clear that the expected result is that only bound attributes will be case-insensitive. The name of the component should still be case sensitive?
Yes, exactly. The component parameters are case-insensitive at runtime, so now the compiler will match that. The component name is a compile-time thing (there is no string matching of the name at runtime) and we definitely want |
I just checked the code and it looks like case-sensitivity for |
@@ -1,7 +1,7 @@ | |||
Source Location: (13:0,13 [11] x:\dir\subdir\Test\TestComponent.cshtml) | |||
|PlaceHolder| | |||
Generated Location: (884:23,0 [11] ) | |||
|PlaceHolder| | |||
|Placeholder| |
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.
Is this correct? The test is specifying PlaceHolder
, but it looks like we're now choosing Placeholder
which seems incorrect?
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.
So, the code that this is testing would fail at runtime anyway with
System.InvalidOperationException: The type 'Component' declares more than one parameter matching the name 'placeholder'. Parameter names are case-insensitive and must be unique.
We are choosing Placeholder
simply because the matching is case-insensitive, so we choose the first one.
I could alternatively implement what you suggested in the issue - matching the casing if there are multiple properties. In fact I already implemented that (see 0a6e708) but then removed it because it just seems redundant if runtime would fail anyway; but I can return it if you think that's better.
From my understanding But that made me think about Note: I'm again updating the baselines in a separate commit so the effect of the product change can be reviewed. |
Hm, EditorRequired parameter matching could be also case-insensitive - but that seems like a separate issue - maybe we want that to be case-sensitive so users can fix the casing to match. I will add tests without changing the behavior in this PR. |
I'm a little confused. The |
@@ -728,17 +728,17 @@ private bool TryParseBindAttribute(BindEntry bindEntry, out string valueAttribut | |||
|
|||
foreach (var attribute in componentTagHelper.BoundAttributes) | |||
{ | |||
if (string.Equals(valueAttributeName, attribute.Name)) | |||
if (string.Equals(valueAttributeName, attribute.Name, StringComparison.OrdinalIgnoreCase)) |
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.
What's the point of setting BoundAttributeDescriptor.CaseSensitive
if we just always do a case-insensitive comparison during lowering? Should we be checking CaseSensitive
here? If not, it'd be good to add a comment why.
FWIW, there's a private helper in TagHelperMatchingConventions
that retrieves the correct StringComparison
based on BoundAttributeDescriptor.CaseSensitive
. If that we're made public, this could be something like this.
foreach (var attribute in componentTagHelper.BoundAttributes)
{
var comparison = attribute.GetComparison();
if (string.Equals(valueAttributeName, attribute.Name, comparison))
{
valueAttribute =
}
if (string.Equals(changeAttributeName, attribute.Name, comparison))
{
changeAttribute = attribute;
}
if (string.Equals(expressionAttributeName, attribute.Name, comparison))
{
expressionAttribute = attribute;
}
}
Also, this algorithm walks forwards and compares every attribute name three times. That could be improved by walking backwards and using three bools to track when valueAttribute
, changeAttribute
, and expressionAttribute
are set. When a bool is set, we can avoid that particular string comparison. When all three are set, we can break out of the loop.
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.
FWIW, there's a private helper in
TagHelperMatchingConventions
that retrieves the correctStringComparison
based onBoundAttributeDescriptor.CaseSensitive
. If that we're made public, this could be something like this.
Yeah, sounds good, I will do that, thanks.
Also, this algorithm walks forwards and compares every attribute name three times. That could be improved by walking backwards and using three bools to track when
valueAttribute
,changeAttribute
, andexpressionAttribute
are set. When a bool is set, we can avoid that particular string comparison. When all three are set, we can break out of the loop.
I can do that as well, thanks. Although I think bools aren't necessary - we can check whether the variables are null.
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.
Although I think bools aren't necessary - we can check whether the variables are null.
Oh yes, you're right. I had misread the code above and my eyes were seeing changedAttributeName
and changedAttribute
as the same.
Yes but the
So no, that should not match and there's a test for that: |
Thanks for verifying that there're tests to validate the behavior. I'm still confused by how this is supposed to work from the implementation, but if there're tests validating the correct behavior, I'm good with it. |
@chsienki for another look, thanks |
Resolves #8854.
Commit-by-commit review might be useful.