2

What would be required to create a case-insensitive string type that otherwise behaves exactly like a string?

I've never heard of anyone making a case insensitive string type like this and it's obviously not part of the framework, but it seems like it could be very useful. The fact that SQL does case insensitive comparisons by default is a great case in point. So I'm thinking it's either not possible, or else there's a really good reason why no one does it that I'm not aware of.

I know it would require using an implicit operator for assignment, and you would have to override the equals operator. And for overriding GetHashCode(), I'm thinking you could just return ToLower().GetHashCode().

What am I missing?

AlG
  • 14,697
  • 4
  • 41
  • 54
BVernon
  • 3,205
  • 5
  • 28
  • 64
  • 2
    You should look at this for string comparisons. https://msdn.microsoft.com/en-us/library/e6883c06(v=vs.110).aspx – deathismyfriend Aug 21 '15 at 17:26
  • 2
    [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – EZI Aug 21 '15 at 17:27
  • 1
    @deathismyfriend In the past I've only needed to do it in a place here or there, but now I'm working on a data upload tool and I literally need it to be case insensitive everywhere. It would be way awesomer to have a type that actually works this way rather than using a utility method if possible. But I agree that's currently the best way I know of to handle it. – BVernon Aug 21 '15 at 17:33
  • @EZI But aren't there a thousand XY problems that never 'needed' to be solved, but they were because it made the code cleaner and the whole programming experience much nicer. – BVernon Aug 21 '15 at 17:37
  • 1
    And you don't know there is not a cleaner solution until you ask the actual question. How is SQL a case in point? SQL just a has a different default. SQL does not have a separate data type for case insensitive char. Why not just try those things you know it would require. – paparazzo Aug 21 '15 at 17:53

3 Answers3

1

Comparing string is rather easy. You can simply use the equals method or the compare method.

Example:

string s = "A";
s.Equals("a", StringComparison.InvariantCultureIgnoreCase); // Will return true.

string s = "A";
s.Equals("a", StringComparison.InvariantCulture); // Will return false.

You should also look at this. That will explain a little more on comparing strings.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
deathismyfriend
  • 2,182
  • 2
  • 18
  • 25
  • 2
    Thanks. I do know how to do case insensitive string comparisons. I would just like a type that has this feature built in so that my code looks cleaner. – BVernon Aug 21 '15 at 17:34
  • You can always add an extension method but i would just use the equals like above. – deathismyfriend Aug 21 '15 at 17:35
1

Building on type of deathismyfriend's answer above, I would extend the string class:

public static class StringExtensions
{
    public static int CaseInsensitveCompare(this string s, string stringToCompare)
    {
        return String.Compare(s, stringToCompare, StringComparison.InvariantCultureIgnoreCase);
    }
}

And the call:

int result = firstString.CaseInsensitveCompare(secondString);
thewisegod
  • 1,524
  • 1
  • 10
  • 11
  • Yeah, this is probably the most practical solution. – BVernon Aug 21 '15 at 18:09
  • Glad to help. If this satisfies your needs please mark as answer. – thewisegod Aug 21 '15 at 18:17
  • Dan, what he's asking for in the original question cannot be done. All of the answers here are alternative solutions. My answer would give you one way to do a case insensitive comparison. Tell me, why would I need to do "if (s1 == s2)" over "int result = s1.CaseInsensitveCompare(s2);" ? But out of every answer here you come to my answer and down vote? Why dude? – thewisegod Oct 11 '15 at 02:49
0

It wouldn't behave "exactly like a string". The string type is special and is baked into the language spec. C# strings exhibit special behavior, such as

  • being a reference type, that gets passed by value. Reference types are normally passed by...well...reference.

  • are interned by default. That means that there is only ever a single instance of a given string. The following code results in the creation of just a single string: a, b and c all point to exactly the same instance of the string quick. That means that Object.ReferenceEquals() is true when comparing any two:

    string a = "The quick brown dog...".Substring(4,5) ;
    string b = new string(new char[]{'q','u','i','c','k'});
    string c = new StringBuilder().
               .Append('q')
               .Append('u')
               .Append('i')
               .Append('c')
               .Append('k')
               .ToString()
               ;
    

[edited to note: while one might think that this should be possible, a little fiddling around suggests that one can't actually create a custom implementation/subtype of CompareInfo as it has no public constructors and its default constructor is internal. More in the answers to this question: Globally set String.Compare/ CompareInfo.Compare to Ordinal

Grrr...]

What you could do is this:

String comparisons are done using the current culture's collation/comparison rules. Create a custom culture for your app, say, a copy of the the US culture that uses the collation/comparison rules you need. Set that as the current culture and Bob's-yer-uncle.

You'll still get compiler/ReSharper whines because you're doing string comparisons without specifying the desired comparison semantics, but your code will be clean.

For more details, see

Community
  • 1
  • 1
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • 1
    Thanks, I guess I actually wouldn't be worried about it acting the same in terms of memory management; but the part about being passed by value is significant, obviously. – BVernon Aug 21 '15 at 17:41
  • 1
    AFAIK your examples of special string behavior are incorrect. 1. **All** C# types are passed by value when passed without modifiers, not just strings (see [C# spec v.5](https://www.microsoft.com/en-us/download/details.aspx?id=7029) section 10.6.1.1 or [msdn:Passing Reference-Type Parameters (C# Programming Guide)](https://msdn.microsoft.com/en-us/library/s6938f28.aspx)). 2. Your example strings `a` `b` `c`, return false when comparing any two with ReferenceEquals. Also, none of them are interned, which you can check by running e.g. `ReferenceEquals(a, string.IsInterned(a))`. – Joel V. Earnest-DeYoung Aug 22 '15 at 10:06