Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does List<T>.IndexOf() perform comparisons on custom objects?

I wrote a class of account objects and hold a static List<T> of those account objects. My program loops through each account in the list, performing some work with the account, and then resetting at the top when it reaches the end of the list.

My issue is that I need to be able to reinsert the account into the list after my program finishes working with it, with some updated info added. Can I do this as written below, using the IndexOf() function to check for the object in the static list or will it fail because I added data to it? I don't understand which fields it compares to see if the two objects are the same.

Note: no duplicates are allowed in the list so there is no risk of updating the wrong item

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);
   }
}
like image 964
blizz Avatar asked Aug 01 '13 20:08

blizz


People also ask

What is List() in C#?

C# - List<T> The List<T> is a collection of strongly typed objects that can be accessed by index and having methods for sorting, searching, and modifying list. It is the generic version of the ArrayList that comes under System.

How does IndexOf work in C#?

In C#, IndexOf() method is a string method. This method is used to find the zero-based index of the first occurrence of a specified character or string within the current instance of the string. The method returns -1 if the character or string is not found.

Why to use list in C#?

Collection. Generic namespace. List class can be used to create a collection of different types like integers, strings etc. List<T> class also provides the methods to search, sort, and manipulate lists.


3 Answers

Another option is to use List.FindIndex, and pass a predicate. That is:

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

That way you can search on any arbitrary field or number of fields. This is especially useful if you don't have access to the source code for Account to add an overloaded Equals method.

like image 82
Jim Mischel Avatar answered Oct 30 '22 13:10

Jim Mischel


One thing the accepted answer did not cover is you are supposed to override Equals(object) and GetHashCode() for IEquatable<T> to work correctly. Here is the full implementation (based off of 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);
    }
}
like image 29
Scott Chamberlain Avatar answered Oct 30 '22 13:10

Scott Chamberlain


Your object should implement the IEquatable interface and override the Equals method.

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);
    }
}
like image 27
keyboardP Avatar answered Oct 30 '22 15:10

keyboardP