-
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
String.Equals isn't intuitive and forces us to do the OrdinalIgnoreCase thing #14065
Comments
I agree +10e8 |
+1 This drives me nuts and forces me to do multi-line |
the default should really be changed as most apps have to have this check |
+1 |
Agreed - lets help our community by making the framework use the correct pattern by default |
var oic = StringComparer.OrdinalIgnoreCase; if (oic.Equals(sort,"Title")) |
I'm not pushing back against this request, but does someone have a strawman to kick off the design? The best thing I can think of is: EqualsOrdinalIgnoreCase as a method on String. Is this still too long? |
Why not EqualsIgnoreCase. Is Ordinal that obvious, or needed? (although semantically it would be implied.) |
@shanselman I guess that's reasonable. Personally I dislike how some operations on the string class do linguistic comparisons where as others do ordinal and it's not clear from the method name what's going on. This proposal would be making the problem worse, but perhaps we should optimize for folks that have already learned for each method if it's doing ordinal or linguistic conversions. |
@ellismg I hear you. I'm trying to optimize for the 80% or even the 90% case. What is the "pit of success" option? What's the one that if folks who don't know the difference pick is more likely to be correct? |
+1 EqualsIgnoreCase |
@rustd Are you suggesting that ignore case should be the default? Changing defaults around this is pretty much a non-starter. We've tried similar things in the past (such as switching all operations to ordinal and invariant by default in Silverlight) but ended up backing it out for a variety of reasons. There's just too much legacy code being copied and pasted around. I like |
@davkean @shanselman Agree on EqualsIgnoreCase. I did a quick scan through the String class, other methods that take a StringComparison overload include What's painfully missing is a Contains overload that accepts a comparison type. It's a bigger functionality gap than EqualsIngoreCase.
This may be a bit more of a stretch, a new IStringEquatable interface could be introduced that inherits from IEquatable. IStringEquatable would add the necessary overloads for the comparison type.
The C# team is currently looking at potentially implementing pattern matching and improvements to the switch statement for C# 7.0. One source of pain has been the inability to do case insensitive comparisons in a switch statement - introducing the interface would provide a hook for case insensitive comparisons as 'syntactic sugar'. The interface could be added to the other string-like types, such as HtmlString. I never quite understood why languages don't introduce a case-insensitive string comparison operator. It's likely that because it only applies to a string, it doesn't meet the bar required for a broadly used language feature. That said, the same was once true for String types themselves (just use an array!). Case-insensitive string comparisons are a very bread & butter development operation, and as noted above can apply to types other than System.String. Imagine the theoretical ==~ and !=~ operators (the tilde being the approximation symbol, not bitwise complement):
Even aside from theoretical language changes (very unlikely), the interface would allow libraries such as LINQ to leverage case-insensitive string equality natively without resorting to reflection. The same holds true for String.Compare, which strangely is missing a non-static |
I love the possible case-insensitive string operators. Until then, let's do On Fri, Feb 6, 2015 at 10:06 AM, Eric Bickle notifications@github.com
Scott Hanselman |
I don't like the operator. It does not really self explain what it does because "approximate equals" is not well defined and could mean many different things. Is "Hello" approximate equals to "Hello!"? The Levensthein distance is 1 so it is approximatly the same, isn't it? If it is implemented for string it will probably be available to be implemented for other types. If I implement a numeric type. is 1 ==~ 0? If im looking at numbers between 0 and 1 its really not. If I am looking at two numbers a and b which are ~10^100 and (a - b) == 1 it is approximatly 0 isnt it? Other than that if(a == |
I don't like the operators myself for the reason mentioned, it isn't something that would be broadly used. As someone who once used Java before moving to C#, I always create an EqualsIgnoreCase() extension method as my shorthand. I think that is the best option here along with a static version. |
Just found this in CoreClr's sstring.h :) BOOL EqualsCaseInsensitive(const SString &s) |
Should we consider both an instance and static method The instance method is great for cases outlined in @shanselman example when one
A static method which considers
The |
Can't folks do this now? That handles the foo is null situation.
On Mon, Feb 9, 2015 at 7:57 AM, Jared Parsons notifications@github.com
Scott Hanselman |
That won't work as typed because it produces a if ((foo?.EqualsIgnoreCase("Whatever")).GetValueOrDefault()) Note: the extra |
I think the other problem with that sample is that |
I would vote for This is already used in a lot of methods in the String class. If "typing less" is the idea, this would match the 80% rule. Honestly, What I would like to see even more is that all methods in the String class follow the same pattern. |
After reading more in this discussion, I'm amazed how this change, that if done like proposed is one of a kind and adds a single different method to a core API just to save some typing, is being accepted like this. Many other simple issues are suffering to pass the "won't change core types like that" review from the team. I'm just a regular guy here and I'm not sure if this was really accepted, but I see a lot of microsoft guys agreeing on this, so that is what it looks like. Now, I think See, the 4th most voted question for C# stackoverflow is about the same problem in String.Contains, with 1079 votes. The same question for String.Equals has only 73 votes. And you are already proposing adding new operators to C# just for that. That's crazy! =) Shouldn't we standardize all methods to accept a |
This thread touches on several important problems in our APIs. I think we should try to address these. But I thing we need a wholistic proposal, not just add an overload here or there. |
Let's not hold this API addition hostage to all the other issues string has. So far, I'm aware of two different, but related issues:
|
@weshaggard @KrzysztofCwalina Any pushback on the proposal for |
And don't forget pls about related Slice[char] operations. |
Am I the only one who thinks Sounds like this opens the door for adding lots of *IgnoreCase methods for other cases. Some methods like So, why not I'm being picky, but I'd like to see less patterns appear just for personal preferences. Much better to just follow what is already there. |
@nvivo, I am not sure if it's bad or not, but I think we need to be super careful adding APIs to such basic types like string. We already have so many options here (comparers, interfaces, delegates, supporting enums, etc.). This is why I said I think we need a holistic approach, i.e. a proposal listing problems with comparison APIs in BCL, paint picture how we would like the APIs to look in the future, and an engineering plan to get us there. @terrajobst, normally I would agree with you, but not in case of System.String. I really don't think we can add APIs to string without proper design/spec (like in the old days) |
Definitely should have operator level support for OrdinalIgnoreCase, i can already write extension methods. We don't need a BCL method, we need an operator |
In my case I do not actually need an operator. I would like to write simple switch for every case I get. But now I end up with multi-chain if...else if... else if... else...if...etc. |
@DmitriySokhach that sounds alot like pattern matching. https://github.com/YangFan789/PatternMatchingExtension might be relevant to you |
+1 |
@shanselman and @terrajobst What was ever the outcome of this... we are doing this a lot in our projects was an extension ever entered in 4.6 or C# 6 feature set. Or are people still creating their own extension methods or operators? |
@DmitriySokhach, you could do this: struct OrdinalIgnoreCaseString : IEquatable<OrdinalIgnoreCaseString>, IEquatable<string> {
string _str;
public OrdinalIgnoreCaseString(string str) {
_str = str;
}
public static implicit operator OrdinalIgnoreCaseString(string str) {
return new OrdinalIgnoreCaseString(str);
}
public static explicit operator string(OrdinalIgnoreCaseString str) {
return str._str;
}
public bool Equals(string other) {
return _str.Equals(other, StringComparison.OrdinalIgnoreCase);
}
public bool Equals(OrdinalIgnoreCaseString other) {
return _str.Equals(other._str, StringComparison.OrdinalIgnoreCase);
}
} |
@KrzysztofCwalina i created this on a gist since this seems like something worth saving! https://gist.github.com/dotnetchris/75f2cf6137b8e0e37961a3301e1dad5b |
@dotnetchris, great; thanks! |
We currently don't have a proposal to review, thus I've marked it as api-needs-work. We'll take a look whether someone on our side will do this. |
Marking as up-for-grabs so that anybody can submit an API Proposal to look at. |
Something that makes this a little bit less painful with C# 6:
|
My personal solution would be to throw our the StringComparison enum completely, and replace all its uses with the StringComparer static instances. All methods that take StringComparison can easily be rewritten using this. The big issue is that you always need a second to thing about which one of the two you need. The typing is not the problem, that's what intellisense/autocomplete is for |
Summarising all the ideas & slipping my cent in :^) I think it's fair to provide static versions of the methods as well since we have them for all the other overloads/methods. 1. Providing an overload of Equals(string) that takes an additional boolean parameter
|
Adding EqualsIgnoreCase() will add more complicity and open a way for bugs I believe. |
This issue is going on six years old and has not had any activity in over a year. We're clearly not going to change the behavior of the existing The proposal that got the most upvotes in this issue was introducing an There are allusions to more fundamental problems with the string APIs and equality checking, but as far as I can tell nobody in this thread has articulated them. If somebody wants to take a stab at clearly explaining the problem, that would help us properly address this issue. Is the problem that we'd prefer the default equality check be ordinal case-insensitive instead of ordinal case-sensitive? (This isn't going to happen.) Is the problem that other string APIs are culture-aware by default? (That's not really relevant to an accelerator for As an example of a language accelerator that requires no API additions, there's always: using static System.StringComparison;
string candidate = ...;
if (candidate.Equals("hello", OrdinalIgnoreCase)) { /* do something */ } If the goal is to avoid writing the literal text |
While I see how adding a case-insensitive version of If a case-insensitive version of Another option I can imagine is to extend @GrabYourPitchforks do you know if there is another issue more in line with what I want? |
Finding a consensus here might be pretty hard. This would allow people to opt-in to their desired comparer really per project. For sure analyzers can solve this, but having to type extra characters all the time to get the proper behavior is just a pain (especially when that behavior should be the default). Furthermore as @divega said, without a solution records are just useless in many scenarios. Implementation wise, Roslyn could probably do the heavy lifting and inject the comparer in all ctors/methods that expect a StringComparison/StringComparer. |
We're doing a sample and we are FOREVER doing this
I think it's time for an overload or an extension that "does the right thing." This is a 10 year old pattern and if the default is wrong (as we tell people to do this) then let's make a better method. Everyone has a version and extension that does this.
The text was updated successfully, but these errors were encountered: