-
Notifications
You must be signed in to change notification settings - Fork 4.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
Analyzer proposal: Consider using String.Equals instead of String.Compare #45552
Comments
@mavasani not sure who could confirm there is indeed a performance issue. |
Perhaps this a more of a code style issue? |
This is a .NET API usage analyzer suggestion. @jeffhandley @carlossanlop @buyaa-n can this please be ported to dotnet/runtime repo and triaged? |
Tagging subscribers to this area: @tarekgh, @safern, @krwq Issue DetailsCode with Diagnostic
Code with Fix
Additional contextSee RCS1235
|
I am not sure why we need this? can you explain more why we need that? both are valid options and both are preferable as long as providing the StringComparison options. I don't think we need that in the analyzers. |
Sure, both are valid options, as @Therzok mentioned above we expect it will give a bit of performance benefit. From that point isn't |
Do we have any benchmark numbers prove that? I am not sure we add any analyzer rules recommend the faster methods. do we? |
not sure, i don't think so
We do, for example CA1836: Prefer |
Ok, prove it is worth it to add such rule. I am not expecting there will be any perf difference and if it does, it will be something ignorable. |
string x = "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss";
string y = "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss";
[Benchmark(Baseline = true)]
public bool Compare()
{
return string.Compare(x, y, StringComparison.CurrentCulture) == 0;
}
[Benchmark]
public bool Equals()
{
return string.Equals(x, y, StringComparison.CurrentCulture);
}
|
@xtqqczze thanks. could you add cases with short strings? and with non-ASCII strings? I am afraid the test case you have used is not the main stream case uses here. |
string x = "🌊🜷🬖🭗🙔🧪🛞💛🃤🚢🐄🂀🪝🔗🜞🚖🅜🟓🚯🄩🌂🁎🎂🮟🃭🍆🥅🁴🌃💵👍🔗🅿🝃🮆🆂🬌🃡📽🙫🍙🦂🔾💛🡻";
string y = "🌊🜷🬖🭗🙔🧪🛞💛🃤🚢🐄🂀🪝🔗🜞🚖🅜🟓🚯🄩🌂🁎🎂🮟🃭🍆🥅🁴🌃💵👍🔗🅿🝃🮆🆂🬌🃡📽🙫🍙🦂🔾💛🡻";
|
@xtqqczze thanks again. I am fine to add the analyzer rule and have it mention this preference is for perf reason. side point, I am really surprised with this difference. I think this suggest String.Compare can be optimized. CC @adamsitnik |
string x = "🌊🡻";
string y = "🌊🡻";
|
Some subtle codegen thing maybe? The codepaths are almost identical https://source.dot.net/#System.Private.CoreLib/String.Comparison.cs,215 Is there a similar difference for other StringComparison types? |
string x = "ff";
string y = "ff";
|
What is surprising, is that the absolute difference in time measurement is considerably greater when the strings are not the same: string x = "ff";
string y = "fx";
|
Disassembly: https://linediff.com/?id=5fcf6f53687f4ba43c8b4567 |
string x = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
string y = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffx";
|
I agree with @tarekgh . I think it would be best to fix the perf issue in dotnet/runtime and simply have no perf issue and no need for the analyzer. @xtqqczze could you please create a new issue in dotnet/runtime with the benchmark code and results attached? If possible, please do provide details about OS version, .NET Version, and culture used. |
@adamsitnik Looking at the disassembly, I think performance of In any case, I think an analyzer still makes sense as |
Sorry, i forgot to mentioned that I agree with @xtqqczze for the benefit of the rule:
I would prefer Equals over Compare, but it is just my personal opinion
I am not the one who will decided it 😄, the final decision will be made in the API review, it might be declined too |
You have to represent the case for the design committee. I mean you need to go and sell that there :-) of course you already know my recommendation here. |
Yep, i got your point, it was a good discussion before API review, thanks! |
I've updated the issue description to propose a new analyzer in the Microsoft.Usage category. |
@xtqqczze You are mentionning that |
I've added some more examples to make this explicit. |
One last question here. does the analyzer will flag a code like: int res = String.Compare(...);
if (res == 0)
{
// ...
} if it does, that will be very wrong except if analyzer will check the reset of the code that the |
We can do either of the following:
@pgovind did an implementation that matches (2) for CA2249: https://github.com/dotnet/roslyn-analyzers/blob/6dea9b867e32607bc02f958efe46d4b2d1220e45/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/PreferStringContainsOverIndexOfAnalyzer.cs#L19 |
@mavasani your proposal is reasonable. if yo go with #1 make sure this will not include. if ((res = string.Compare(....)) == 0)
{
} |
I think it would be worthwhile to have a separate analyzer to flag redundant assignment, like RCS1212. If we had such an analyzer, rules like |
@xtqqczze The assignment above is not redundant, |
@buyaa-n Sounds good to me. I think it will cover most realistic user code. |
I would like to be assigned to this, please. |
@buyaa-n This was already implemented. Should it be closed now? |
Category: Microsoft.Usage
Fix is breaking or non-breaking: Non-breaking
Cause
This rule locates calls to
Compare
where the result is used to check for equality, and suggests usingEquals
instead, to improve readability.Rule description
When Compare is used to check if the result is equal to
0
, the call can be safely substituted with Equals.String.Compare(string)
String.Equals(string)
String.Compare(string, false)
String.Equals(string, StringComparison.CurrentCulture)
String.Compare(string, true)
String.Equals(string, StringComparison.CurrentCultureIgnoreCase)
String.Compare(string, StringComparison)
String.Equals(string, StringComparison)
Examples
Code with Diagnostic
Code with Fix
When to suppress warnings
It's safe to suppress a violation of this rule if improving code readability is not a concern.
Additional context
The text was updated successfully, but these errors were encountered: