简体   繁体   English

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

[英]Dictionary using an object as a key C#

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; }
}

Then at some point I would like to search for the int by creating an ExcelCellIdentifier object with the same ticker and identifier, like: 然后在某个时候,我想通过创建具有相同代码和标识符的ExcelCellIdentifier对象来搜索int,例如:

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

Is this possible? 这可能吗?

From the documentation : 文档中

Dictionary<TKey, TValue> requires an equality implementation to determine whether keys are equal. Dictionary<TKey, TValue>需要一个相等实现来确定键是否相等。 You can specify an implementation of the IEqualityComparer<T> generic interface by using a constructor that accepts a comparer parameter; 您可以通过使用接受比较器参数的构造函数来指定IEqualityComparer<T>通用接口的实现 if you do not specify an implementation, the default generic equality comparer EqualityComparer<T>.Default is used. 如果未指定实现,则使用默认的泛型相等比较器EqualityComparer<T>.Default If type TKey implements the System.IEquatable<T> generic interface, the default equality comparer uses that implementation. 如果类型TKey实现System.IEquatable<T>通用接口,则默认的相等比较器将使用该实现。

It's up to you to decide how you want equality to work in this case - either provide a comparer when you construct the dictionary or implement IEquatable<T> . 在这种情况下,您需要决定希望平等的工作方式-在构造字典时提供比较器或实现IEquatable<T> The middle option doesn't work for you, since the default comparer for reference types uses reference equality. 中间选项对您不起作用,因为引用类型的默认比较器使用引用相等。

yes, you can do this as long as you either implement IEquatable<ExcelCellIdentifier> in your ExcelCellIdentifier class, or instantiate the dictionary with an instance of IEqualityComparer<ExcelCellIdentifier> . 是的,只要您在ExcelCellIdentifier类中实现IEquatable<ExcelCellIdentifier>或使用IEqualityComparer<ExcelCellIdentifier>的实例实例化字典,就可以执行此操作。

One important thing to remember is that although I don't think IEquatable<T> forces you to override GetHashCode() (even though as commented below it's mandated in the documentation), you need to make sure you override it appropriately, otherwise even if your objects return true for Equals() , one won't work as a key to find the other in the dictionary. 要记住的重要一件事是,尽管我不认为IEquatable<T>强迫您重写GetHashCode() (即使如下文文档中所强制要求的那样),但您仍需要确保适当地重写它,否则即使您的对象对于Equals()返回true,一个对象不能用作在字典中查找另一个对象的键。

This is a cause of lots of fun debugging where you're sure your equality comparer is working fine, but somehow your dictionary isn't retrieving anything! 这是很多有趣的调试过程的原因,在此过程中,您确定相等比较器可以正常工作,但是以某种方式字典无法检索任何内容!

For my money, I prefer to implement a custom equality comparer, which keeps the business of managing your dictionary separate from the implementation of your class: 为了我的钱,我更喜欢实现一个自定义的相等比较器,该比较器使管理字典的工作与类的实现分开进行:

    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();
        }
    }

Because no one else has given you a proper version using IEquateable here you go 因为没有人使用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);
   }
}

Change these two methods to the following to remove case sensitivity to the strings 将这两种方法更改为以下内容以消除对字符串的区分大小写

   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);
   }

as Damien_The_Unbeliever said, what you need is: 如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();
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM