2010-11-17 42 views
2

J'ai créé une structure C# qui peut gérer de façon générique des comparaisons de chaînes insensible à la casse, de manière transparente. Ainsi, par exemple:Insensible à la casse comparer chaîne à non-chaîne

List<IString> list = new List<IString>(); 
list.Add("help"); 
Assert.IsTrue(list.Contains("Help")); 

ou

Dictionary<IString, string> dict = new Dictionary<IString, string>(); 
dict["Help"] = "thanks!"; 
Assert.AreEqual("thanks!", dict["hELP"]); 

Mais la seule chose que je ne peux pas comprendre (et peut-être il est impossible), est comment obtenir la chaîne de classe pour jouer bien dans Equals (objet):

IString A1 = "A"; 
string A2 = "a"; 
Assert.AreEqual(A1, A2, "This passes"); 
Assert.AreEqual(A2, A1, "This fails"); 

Voici le code:

using System; 
using System.Collections.Generic; 

namespace Util 
{ 
    /// <summary> 
    /// Case insensitive wrapper for the string class 
    /// </summary> 
    public struct IString : 
     IComparer<IString>, 
     IComparable, 
     IComparable<IString>, 
     IComparable<string>, 
     IEquatable<string>, 
     IEquatable<IString> 
    { 
     private const StringComparison icase = StringComparison.OrdinalIgnoreCase; 

     public readonly string Value; 
     public IString(string Value) 
     { 
      this.Value = Value; 
     } 

     public bool Equals(string Other) 
     { 
      return string.Equals(Value, Other, icase); 
     } 
     public bool Equals(IString Other) 
     { 
      return string.Equals(Value, Other.Value, icase); 
     } 
     public override bool Equals(object obj) 
     { 
      if (obj is IString || obj is string) 
      { 
       return string.Equals(Value, obj.ToString(), icase); 
      } 
      else 
      { 
       return false; 
      } 
     } 

     public int IndexOf(string Other) 
     { 
      return Other.IndexOf(Other, icase); 
     } 
     public bool Contains(string Other) 
     { 
      return IndexOf(Other) >= 0; 
     } 

     public override int GetHashCode() 
     { 
      if (Value == null) 
       return 0; 
      else 
       return StringComparer.OrdinalIgnoreCase.GetHashCode(Value); 
     } 

     public override string ToString() 
     { 
     return Value; 
     } 

     public int Compare(IString x, IString y) 
     { 
      return string.Compare(x.Value, y.Value, icase); 
     } 
     public int Compare(string x, string y) 
     { 
      return string.Compare(x, y, icase); 
     } 

     public int CompareTo(object obj) 
     { 
      if (obj is IString) 
       return Compare(this, (IString)obj); 
      else if (obj is string) 
       return Compare(Value, (string)obj); 
      else if (Value != null) 
       return Value.CompareTo(obj); 
      else 
       return -1; 
     } 

     public int CompareTo(IString other) 
     { 
      return Compare(this, other); 
     } 

     public int CompareTo(string other) 
     { 
      return Compare(Value, other); 
     } 

     public static implicit operator string(IString From) 
     { 
      return From.Value; 
     } 
     public static implicit operator IString(string From) 
     { 
      return new IString(From); 
     } 

     #region IString to IString operators 
     public static bool operator ==(IString Str1, IString Str2) 
     { 
      return string.Equals(Str1.Value, Str2.Value, icase); 
     } 
     public static bool operator !=(IString Str1, IString Str2) 
     { 
      return !string.Equals(Str1.Value, Str2.Value, icase); 
     } 
     public static IString operator +(IString Str1, IString Str2) 
     { 
      return (IString)(Str1.Value + Str2.Value); 
     } 
     public static bool operator >(IString Str1, IString Str2) 
     { 
      return Str1.CompareTo(Str2) > 0; 
     } 
     public static bool operator >=(IString Str1, IString Str2) 
     { 
      return Str1.CompareTo(Str2) >= 0; 
     } 
     public static bool operator <(IString Str1, IString Str2) 
     { 
      return Str1.CompareTo(Str2) < 0; 
     } 
     public static bool operator <=(IString Str1, IString Str2) 
     { 
      return Str1.CompareTo(Str2) <= 0; 
     } 
     #endregion IString to IString operators 


     #region string to IString operators 
     public static bool operator ==(string Str1, IString Str2) 
     { 
      return string.Equals(Str1, Str2.Value, icase); 
     } 
     public static bool operator !=(string Str1, IString Str2) 
     { 
      return !string.Equals(Str1, Str2.Value, icase); 
     } 
     public static IString operator +(string Str1, IString Str2) 
     { 
      return (IString)(Str1 + Str2.Value); 
     } 
     public static bool operator >(string Str1, IString Str2) 
     { 
      return Str2.CompareTo(Str1) < 0; 
     } 
     public static bool operator >=(string Str1, IString Str2) 
     { 
      return Str2.CompareTo(Str1) <= 0; 
     } 
     public static bool operator <(string Str1, IString Str2) 
     { 
      return Str2.CompareTo(Str1) > 0; 
     } 
     public static bool operator <=(string Str1, IString Str2) 
     { 
      return Str2.CompareTo(Str1) >= 0; 
     } 
     #endregion string to IString operators 


     #region IString to string operators 
     public static bool operator ==(IString Str1, string Str2) 
     { 
      return string.Equals(Str1.Value, Str2, icase); 
     } 
     public static bool operator !=(IString Str1, string Str2) 
     { 
      return !string.Equals(Str1.Value, Str2, icase); 
     } 
     public static IString operator +(IString Str1, string Str2) 
     { 
      return (IString)(Str1.Value + Str2); 
     } 
     public static bool operator >(IString Str1, string Str2) 
     { 
      return Str1.CompareTo(Str2) > 0; 
     } 
     public static bool operator >=(IString Str1, string Str2) 
     { 
      return Str1.CompareTo(Str2) >= 0; 
     } 
     public static bool operator <(IString Str1, string Str2) 
     { 
      return Str1.CompareTo(Str2) < 0; 
     } 
     public static bool operator <=(IString Str1, string Str2) 
     { 
      return Str1.CompareTo(Str2) <= 0; 
     } 
     #endregion IString to string operators 

    } 
} 

Y at-il un moyen d'obtenir string.Equal (objet) pour traiter réellement IString comme une chaîne?

+0

Vous devez utiliser 'OrdinalIgnoreCase' au lieu de' InvariantCultureIgnoreCase'; c'est plus rapide et plus sûr. – SLaks

+0

Aussi, 'return StringComparer.OrdinalIgnoreCase.GetHashCode (Value);'. – SLaks

+0

Autre que cela, et le fait que ce n'est pas nécessaire en premier lieu, votre structure semble plutôt bonne. – SLaks

Répondre

9

Vous n'avez pas besoin de créer un tel type en premier lieu.
Au lieu de cela, vous devez utiliser la classe StringComparer.

Par exemple:

var dict = new Dictionary<String, string>(StringComparer.OrdinalIgnoreCase); 
dict["Help"] = "thanks!"; 
Assert.AreEqual("thanks!", dict["hELP"]); 

Ou

List<String> list = new List<String>(); 
list.Add("help"); 
Assert.IsTrue(list.Contains("Help", StringComparer.OrdinalIgnoreCase)); 

Notez également qu'il ne devrait pas être nommé IString; seules les interfaces doivent commencer par I.

Pour répondre à votre question, non; c'est impossible.

2

Non, il n'y en a pas. La méthode String.Equals(object) a une dépendance dure sur la valeur fournie étant du type String. Il effectue une vérification de type CLR qui ne tient pas compte des conversions ou fonctions définies par l'utilisateur et ne fonctionnera donc qu'avec une instance de System.String