List <t> .IndexOf()如何对自定义对象执行比较?</t>

时间:2013-08-01 20:27:18

标签: c# .net generics collections

我编写了一类帐户对象并保留了这些帐户对象的静态List<T>。我的程序循环遍历列表中的每个帐户,对帐户执行一些操作,然后在到达列表末尾时在顶部重置。

我的问题是,在我的程序完成后,我需要能够将帐户重新插入列表中,并添加了一些更新的信息。我是否可以按照下面的说明执行此操作,使用IndexOf()函数检查静态列表中的对象,还是因为我向其添加数据而失败?我不明白它比较哪些字段以查看两个对象是否相同。

注意:列表中不允许重复,因此不存在更新错误项目的风险

public class Account
{
   public string name;
   public string password;
   public string newInfo;
}

public static class Resources
{
   private static List<Account> AccountList = new List<Account>();
   private static int currentAccountIndex = 0;

   public static Account GetNextAccount()
   {
      if (currentAccountIndex > AccountList.Count)
         currentAccountIndex = 0;
      return AccountList[currentAccountIndex++];
   }

   public static void UpdateAccount(Account account)
   {
      int index;
      if ((index = AccountList.IndexOf(account)) >= 0)
         AccountList[index] = account;
   }
}

public class Program
{
   public void PerformWork()
   {
      Account account = Resources.GetNextAccount();
      // Do some work
      account.newInfo = "foo";
      Resources.UpdateAccount(account);
   }
}

5 个答案:

答案 0 :(得分:9)

另一种选择是使用List.FindIndex,并传递一个谓词。那就是:

if ((index = AccountList.FindIndex(a => a.name == account.name)) >= 0)
    AccountList[index] = account;

通过这种方式,您可以搜索任意字段或字段数。如果您无权访问Account的源代码以添加重载的Equals方法,则此功能特别有用。

答案 1 :(得分:8)

您的对象应实现IEquatable接口并覆盖Equals方法。

public class Account : IEquatable<Account>
{
    public string name;
    public string password;
    public string newInfo;

    public bool Equals(Account other)
    {
       //Choose what you want to consider as "equal" between Account objects  
       //for example, assuming newInfo is what you want to consider a match
       //(regardless of case)
       if (other == null) 
             return false;

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

答案 2 :(得分:4)

如果您的班级正确实施IEquatable<T>,那么IndexOf()将使用您的Equals()方法来测试是否相等。

否则,IndexOf()将使用引用相等。

答案 3 :(得分:4)

接受的答案没有涉及的一件事是你应该覆盖Equals(object)GetHashCode()以使IEquatable<T>正常工作。这是完整的实现(基于keyboardP's answer

public class Account : IEquatable<Account>
{
    public string name;
    public string password;
    public string newInfo;

    private readonly StringComparer comparer = StringComparer.OrdinalIgnoreCase;

    public override bool Equals(object other)
    {
        //This casts the object to null if it is not a Account and calls the other Equals implementation.
        return this.Equals(other as Account);
    }

    public override int GetHashCode()
    {
        return comparer.GetHashCode(this.newInfo)
    }

    public bool Equals(Account other)
    {
       //Choose what you want to consider as "equal" between Account objects  
       //for example, assuming newInfo is what you want to consider a match
       //(regardless of case)
       if (other == null) 
             return false;

       return comparer.Equals(this.newInfo, other.newInfo);
    }
}

答案 4 :(得分:0)

您可以为类使用自定义谓词,例如:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

然后您可以按以下方式使用它:

public class Account
{
  public string name;
  public string password;
  public string newInfo;

  public class IndexOfName
  {
    private string _match = "";

    public IndexOfName()
    {
    }

    public Predicate<Account> Match(string match)
    {
      this._match = match;
      return IsMatch;
    }

    private bool IsMatch(Account matchTo)
    {
      if (matchTo == null)
      {
        return false;
      }
      return matchTo.Equals(this._match);
    }
  }
}

您甚至可以更改IndeOfName类,以使用标志在要查找的信息类型之间切换。例如:名称或newInfo。

相关问题