2014-09-23 73 views
0

我使用dictionary<string,string>。 鍵是一個url,Value是一個名字。字典避免使用相同的鍵值類型

由於類型相同,我尋找一種方法來避免編碼錯誤時的鍵值倒置。 我想要這樣的Dictionary<UrlString,NameString>,但我不能創建我自己的字符串類型繼承,因爲是密封的。

那麼有沒有簡單的方法? 感謝

+1

嘗試['Url'](http://msdn.microsoft.com/en-us/library/system.security.policy .url(v = vs.110).aspx)類型。甚至是['Uri'](http://msdn.microsoft.com/zh-cn/library/system.uri(v = vs.110).aspx)類型。當然是 – 2014-09-23 08:02:11

+0

!!我感覺很蠢..謝謝 – Julian50 2014-09-23 08:05:19

+0

@AndreiV這種情況確定,因爲URL存在!但例如字典與關鍵是一個id和值是一個大小? – Julian50 2014-09-23 08:07:56

回答

2

首先,你可以使用Uri

http://msdn.microsoft.com/en-us/library/system.uri(v=vs.110).aspx

但是,你可以設計自己的類,你所要做的 是落實以EqualsGetHashCode的唯一的事情使用該類作爲 字典密鑰

// You can implement in the same manner whatever domain you want: 
// Url, Size, Id, Voltage etc. 
public sealed class UrlString { 
    public UrlString(String address) { 
    if (Object.ReferenceEquals(null, address)) 
     throw new ArgumentNullException("address"); 

    Address = address; 
    } 

    public String Address { 
    get; 
    private set; 
    } 

    public override Boolean Equals(Object obj) { 
    if (Object.ReferenceEquals(obj, this)) 
     return true; 

    UrlString other = obj as UrlString; 

    if (Object.ReferenceEquals(other, null)) 
     return false; 

    return String.Equals(Address, other.Address, StringComparison.OrdinalIgnoreCase); 
    } 

    public override int GetHashCode() { 
    return String.IsNullOrEmpty(Address) ? 0 : Address.ToUpperInvariant().GetHashCode(); 
    } 
} 
+0

非常感謝! – Julian50 2014-09-23 08:16:18

0

一般來說,爲業務功能定製集合不是一個好習慣,最好是實現一些自定義方法,但是您當然可以。

我可以弄清楚至少有兩種方法。 1.使用具有隱式轉換運算符的自定義結構,該運算符執行構造函數中的檢查。適用於值類型。 2.使用IEqualityComparer更好,因爲它不改變初始IDictionary簽名。

下面是代碼樣品與試驗兩種變體:

using System; 
using System.Collections.Generic; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace LimitingUseOfValueTypeAsDictionaryKey 
{ 
    public struct MySpecialInt 
    { 
     public int Target; 

     public MySpecialInt(int source) 
     { 
      if (source == 123) 
      { 
       throw new ArgumentOutOfRangeException("source"); 
      } 
      Target = source; 
     } 

     public static implicit operator int(MySpecialInt source) 
     { 
      return source.Target; 
     } 

     public static implicit operator MySpecialInt(int source) 
     { 
      return new MySpecialInt(source); 
     } 
    } 

    public class LimitingIntComparer : IEqualityComparer<int> 
    { 
     public int Compare(int x, int y) 
     { 
      return x.CompareTo(y); 
     } 

     public bool Equals(int x, int y) 
     { 
      return x.Equals(y); 
     } 

     public int GetHashCode(int source) 
     { 
      if (source == 123) 
      { 
       throw new ArgumentOutOfRangeException("source"); 
      } 
      return source.GetHashCode(); 
     } 
    } 

    public class LimitingStringComparer : IEqualityComparer<string> 
    { 
     public bool Equals(string x, string y) 
     { 
      return object.Equals(x, y); 
     } 

     public int GetHashCode(string source) 
     { 
      if (source == "123") 
      { 
       throw new ArgumentOutOfRangeException("source"); 
      } 
      return source.GetHashCode(); 
     } 
    } 

    [TestClass] 
    public class UnitTest1 
    { 
     [TestMethod] 
     public void CanTreatMySpecialIntAsRegularInt() 
     { 
      var a = 1; 
      MySpecialInt b = a; 
      Assert.AreEqual((int)b, 1); 
     } 

     [TestMethod] 
     public void CanUseOnlyAllowedValuesAsAKeyUsingCustomStruct() 
     { 
      var d = new Dictionary<MySpecialInt, string>(); 
      d.Add(1, "foo"); 

      try 
      { 
       d.Add(123, "bar"); 
      } 
      catch (ArgumentOutOfRangeException) 
      { 
       Console.WriteLine("Can't do that"); 
      } 

      Assert.AreEqual(1, d.Count); 
      Assert.AreEqual("foo", d[1]); 
     } 

     [TestMethod] 
     public void CanUseOnlyAllowedValuesAsAKeyUsingUsingComparer() 
     { 
      var d = new Dictionary<int, string>(new LimitingIntComparer()); 
      d.Add(1, "foo"); 

      try 
      { 
       d.Add(123, "bar"); 
      } 
      catch (ArgumentOutOfRangeException) 
      { 
       Console.WriteLine("Can't do that"); 
      } 

      Assert.AreEqual(1, d.Count); 
      Assert.AreEqual("foo", d[1]); 
     } 

     [TestMethod] 
     public void CanUseOnlyAllowedValuesAsAKeyUsingUsingComparerForStrings() 
     { 
      var d = new Dictionary<string, string>(new LimitingStringComparer()); 
      d.Add("1", "foo"); 

      try 
      { 
       d.Add("123", "bar"); 
      } 
      catch (ArgumentOutOfRangeException) 
      { 
       Console.WriteLine("Can't do that"); 
      } 

      Assert.AreEqual(1, d.Count); 
      Assert.AreEqual("foo", d["1"]); 
     } 
    } 
}