使用对象作为关键字C#的字典

时间:2013-07-16 14:14:24

标签: c# dictionary

private readonly Dictionary<ExcelCellIdentifier, int> allInfoByIdentifier = new Dictionary<ExcelCellIdentifier, int>();

public class ExcelCellIdentifier
{
    public ExcelCellIdentifier(string ticker, string identifier)
    {
        Ticker = ticker;
        Identifier = identifier;
    }
    public string Ticker { get; set; }
    public string Identifier { get; set; }
}

然后在某些时候我想通过创建一个具有相同股票代码和标识符的ExcelCellIdentifier对象来搜索int,例如:

ExcelCellIdentifier ex = new ExcelCellIdentifier("Ticker1", "Identifier1");
int a = allInfoByIdentifier[ex];
//a is a value stored before hand

这可能吗?

4 个答案:

答案 0 :(得分:3)

来自documentation

  

Dictionary<TKey, TValue>需要一个相等的实现来确定密钥是否相等。您可以使用接受 comparer 参数的构造函数指定IEqualityComparer<T>泛型接口的实现;如果未指定实现,则使用默认的通用相等比较器EqualityComparer<T>.Default。如果类型 TKey 实现System.IEquatable<T>通用接口,则默认的相等比较器使用该实现。

由您来决定在这种情况下您希望如何平等 - 在构造字典时提供比较器或实现IEquatable<T>。中间选项不适合您,因为引用类型的默认比较器使用引用相等。

答案 1 :(得分:1)

是的,只要您在IEquatable<ExcelCellIdentifier>类中实现ExcelCellIdentifier,或者使用IEqualityComparer<ExcelCellIdentifier>实例实例化字典,就可以执行此操作。

要记住的一件重要事情是,虽然我不认为IEquatable<T>会强制您覆盖GetHashCode()(即使下面注释了它在文档中的强制要求),您需要确保覆盖它是恰当的,否则即使你的对象对Equals()返回true,也不能作为在字典中找到另一个的关键。

这是一个很有趣的调试的原因,你确定你的相等比较器工作正常,但不知何故你的字典没有检索任何东西!

为了我的钱,我更喜欢实现自定义的相等比较器,这使得管理字典的业务与您的类的实现分开:

    private readonly Dictionary<ExcelCellIdentifier, int> allInfoByIdentifier =
        new Dictionary<ExcelCellIdentifier, int>(new ExcelCellIdentifierComparer());

    public class ExcelCellIdentifier
    {
        private ExcelCellIdentifier(string ticker, string identifier)
        {
            Ticker = ticker;
            Identifier = identifier;
        }

        public string Ticker { get; set; }

        public string Identifier { get; set; }

    }

    private class ExcelCellIdentifierComparer : IEqualityComparer<ExcelCellIdentifier>
    {
        public bool Equals(ExcelCellIdentifier x, ExcelCellIdentifier y)
        {
            return x.Identifier == y.Identifier && x.Ticker == y.Ticker;
        }

        public int GetHashCode(ExcelCellIdentifier obj)
        {
            return obj.Identifier.GetHashCode() ^ obj.Ticker.GetHashCode();
        }
    }

答案 2 :(得分:1)

因为没有其他人在这里使用IEquateable给你一个合适的版本你去

public class ExcelCellIdentifier : IEquatable<ExcelCellIdentifier>
{
   public ExcelCellIdentifier(string ticker, string identifier)
   {
        Ticker = ticker;
        Identifier = identifier;
   }

   public override bool Equals(object obj)
   {
      var identifier = obj as ExcelCellIdentifier;
      if(identifier == null)
          return false;
      else
          return Equals(identifier);
   }

   public override int GetHashCode()
   {
      //All this below is a common performance thing I add, if you have the two strings "Foo" and "Bar" it will give you a different hash code than the string "Bar" and "Foo", it gives you a better distribution of the hash.
      unchecked
      {
          int hash = 17;
          hash = hash * 23 + Ticker.GetHashCode();
          hash =  hash * 23 + Identifier.GetHashCode();
          return hash;
      }
   }

   public string Ticker { get; set; } //This should likely be changed to {get; private set;}
   public string Identifier { get; set; } //This should likely be changed to {get; private set;}

   public bool Equals(ExcelCellIdentifier other)
   {
      return Ticker.Equals(other.Ticker) && Identifier.Equals(other.Identifier);
   }
}

将这两个方法更改为以下内容以消除对字符串的区分大小写

   public override int GetHashCode()
   {
      //All this below is a common performance thing I add, if you have the two strings "Foo" and "Bar" it will give you a different hash code than the string "Bar" and "Foo", it gives you a better distribution of the hash.
      unchecked
      {
          int hash = 17;
          hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(Ticker);
          hash =  hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(Identifier);
          return hash;
      }
   }

   public string Ticker { get; set; } //This should likely be changed to {get; private set;}
   public string Identifier { get; set; } //This should likely be changed to {get; private set;}

   public bool Equals(ExcelCellIdentifier other)
   {
      return StringComparer.OrdinalIgnoreCase.Equals(Ticker, other.Ticker) && StringComparer.OrdinalIgnoreCase.Equals(Identifier, other.Identifier);
   }

答案 3 :(得分:0)

Damien_The_Unbeliever说,你需要的是:

public class myClass
{
  private readonly Dictionary<ExcelCellIdentifier, int> allInfoByIdentifier =
  new Dictionary<ExcelCellIdentifier, int>(new ExcelCellIdentifier());

  public void testIt()
  {
     allInfoByIdentifier.Add(new ExcelCellIdentifier("Ticker1", "Identifier1"), 4);
     ExcelCellIdentifier ex = new ExcelCellIdentifier("Ticker1", "Identifier1");
     int a = allInfoByIdentifier[ex];
  }
}

   public class ExcelCellIdentifier : IEqualityComparer<ExcelCellIdentifier>
{
  public ExcelCellIdentifier()
  {

  }
    public ExcelCellIdentifier(string ticker, string identifier)
    {
        Ticker = ticker;
        Identifier = identifier;
    }

    public string Ticker { get; set; }

    public string Identifier { get; set; }

    public bool Equals(ExcelCellIdentifier x, ExcelCellIdentifier y)
    {
       return x.Identifier == y.Identifier && 
          x.Ticker == y.Ticker;
    }

    public int GetHashCode(ExcelCellIdentifier obj)
    {
       return obj.Identifier.GetHashCode() ^ 
          obj.Ticker.GetHashCode();
    }

}