-1

UseCase: In recent code fixes, I observed that the developer did not take care of converting the case of strings uniformly before strings comparison and this has caused bugs in the production environment.

This triggered me a need to override the default Equals() method at namespace scope for already existing code where hundreds of places string comparisons are happening.

Before I go and fix manually at more than 400+ places, I was trying with these approaches, but could not find the satisfactory result.

Approach1:
Problem: It requires new method name -> NewEquals(). This requires changes in all the classes.

We can't use 'Equals()' here as instance method takes higher precedence.

class Program
{
    static void Main(string[] args)
    {
        string strFromConfig = "sometext";
        const string str = "SomeText";

        Console.WriteLine(str.Equals(strFromConfig));   // False
        Console.WriteLine(str.NewEquals(strFromConfig));    // True
    }
}
static class StringCompare      // Extension method approach
{
    public static bool NewEquals(this string str, string strconfig)
    {
        // edited this as per the suggestion in the comments.
        return str.Equals(strconfig, StringComparison.OrdinalIgnoreCase);
    }        
}

Approach2:

Problem: Maybe I am making some mistake in overriding Equals().

Even if it works, it has one con that this overridden function won't be available within the namespace. And hence it won't fix in all the classes.

class Program
{
    static void Main(string[] args)
    {
        string strFromConfig = "sometext";
        const string str = "SomeText";

        Console.WriteLine(str.Equals(strFromConfig));  // False

        // This also doesn't invoke overridden method.
        Console.WriteLine(str.Equals((object)strFromConfig));  // False
    }
    public override bool Equals(object obj)
    {   //  Program control doesn't enter here. So could not test the below two returns.
        return base.Equals(obj);
        //return base.ToString().ToLower().Equals(obj.ToString().ToLower());
    }
}

Can someone please help me in knowing is it feasible to achieve what I am looking for -> One change - many fixes.

Koder101
  • 844
  • 15
  • 28
  • 1
    `str.NewEquals(strFromConfig)); // True` - that is an utterly terrible idea. Also behaviour that is dependant on the containing namespace is equally terrible –  Dec 30 '17 at 06:48
  • @MickyD : I understand it's terrible, but even this works, does not solve my problem. – Koder101 Dec 30 '17 at 06:51
  • Your question is all wrong. You are worried about being able to implement in a uniform way a completely wrong choice for your string comparison. If you want case-insensitive string comparisons, you should use an actual case-insensitive string comparison. Converting case is _not_ the right way to go about that. See e.g. https://stackoverflow.com/questions/631233/is-there-a-c-sharp-case-insensitive-equals-operator and https://stackoverflow.com/questions/10797309/case-insensitive-comparison-in-c-sharp. – Peter Duniho Dec 30 '17 at 07:09
  • Doing the comparisons correctly will still involve changing a lot of code, but at least you'll be going in the right direction. As far as what the best way to change that code would be, you haven't provided enough detail here to know. It really depends on what these strings are, how they are being compared, and why you want the case-insensitive comparison. – Peter Duniho Dec 30 '17 at 07:11
  • @PeterDuniho : The default string comparisons in code looks like this -> str.Equals(strFromConfig), which fails in case of case differences. The string are coming from config files and being compared with internal constant strings. In case the user changes the case in the config file, then it fails. – Koder101 Dec 30 '17 at 07:14
  • _"which fails in case of case differences"_ -- of course it does. That's not the point. The point is, if you want case-insensitive comparisons, you should be using the overload that allows you to specify a case-insensitive comparison, **not changing the case of the string**. – Peter Duniho Dec 30 '17 at 07:17
  • @PeterDuniho : Yes I agree, but even to implement *StringComparison.CurrentCultureIgnoreCase* would require manual changes at all the places. This is not a new development, dealing with the already existing codebase. – Koder101 Dec 30 '17 at 07:19
  • In other words, anywhere you have `str.ToLower().Equals(strFromConfig)` or something similar, you should instead have `str.Equals(strFromConfig, StringComparison.OrdinalIgnoreCase)` (other options include `CurrentCultureIgnoreCase` and `InvariantCultureIgnoreCase`, but given that the strings appear to be text for the machine and not the user, an ordinal comparison is probably most appropriate). – Peter Duniho Dec 30 '17 at 07:19
  • Of course it would require a manual change at all the places. Too bad...the code is **broken** now, and needs to be changed anyway. Bottom line: you need to fix the code, and there's no way to globally override the default comparison (well, I guess you could use AOP like PostSharp or something, but talk about swatting a fly with a sledgehammer...) – Peter Duniho Dec 30 '17 at 07:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/162208/discussion-between-koder101-and-peter-duniho). – Koder101 Dec 30 '17 at 07:22

1 Answers1

1

If you’re not looking for culture aware comparisons use this

string.Equals(val1, val2, StringComparison.OrdinalIgnoreCase)

Also make a wrapper around your configuration system, and let all classes use this wrapper for access to the app/web.configs. Like this

public class Configuration: IConfiguration
{
   public Configuration
   {
     this.Foo = ConfigurationManager.AppSettings["MyConfig"];
   }
   public string Foo { get; private set; }
   public bool IsMatch(string str) { return string.Equals(str, this.Foo, StringComparison.OrdinalIgnoreCase); } } 
}

Then you can inject an instance of IConfiguration to any class constructor you use in your project.

I would strongly advise not making any overloads to Equal. The tooling for what you want is already in the BCL so why reinvent the wheel. It might be a pain doing 400+ replacements, but tools like Resharper can help, or just do a simple find and replace. I would want to inspect any code changes anyway before production.

M Raymaker
  • 1,231
  • 5
  • 14
  • 31