1

I have this class on my c# console application

public class Person 
{
    public Person(int id , string l, string f)
    {
            FirstName = f;
            LastName = l;
            Id = id;
    }

    public int Id {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
}

In my Main method I have the following code:

 public  static void Main(string[] args)
        {

            Person[] p = new Person[3];

            p[0] = new Person(8,"John", "Doe");
            p[1] = new Person(9,"Adam", "Cas");
            p[2] = new Person(1,"Oliver", "Anderson");

            Array.Sort(p); // this doesn't work, i get InvalidOperationException
      }

If it is array of simple types like string , int,..etc i can easily use Array.Sort(myarray) and then it will be sorted.But when i use Array.Sort(p) i get an exception (InvalidOperationException).

Indeed this is expected exception as documentation on Array.Sort says

InvalidOperationException One or more elements in array do not implement the IComparable interface.

Unfortunately all samples show how to implement IComparer for string while I need to be able to sort by a string property of the object ( Id, FirstName, LastName ). And there is no sample of IComparable which my objects presumably need to imlement.

Here is a sample from the documentation:

public class ReverseComparer : IComparer
{
   // Call CaseInsensitiveComparer.Compare with the parameters reversed.
   public int Compare(Object x, Object y)
   {
       return (new CaseInsensitiveComparer()).Compare(y, x );
   }
}

There are indeed samples of IComparer (like Using IComparer for sorting) but they show IComparer<T>... There is also sample of IComparable is corresponding documentation IComparable but that one is for temperature with non-string properties.

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
Hardood
  • 503
  • 1
  • 5
  • 15
  • 3
    Does this answer your question? [How do you implement IComparable to sort an array of a custom type?](https://stackoverflow.com/questions/24580822/how-do-you-implement-icomparable-to-sort-an-array-of-a-custom-type) – devNull May 10 '20 at 01:13
  • @devNull to sort i want to choose one of my properties to sort, either Id, or FirstName, or LastName. – Hardood May 10 '20 at 01:17

3 Answers3

1

this error makes sense because you are trying to sort a complex object, how do you compare an object to another object, what you can do is use an IComparable <T> comparison interface to be able to compare two objects as shown in the code below:

public  static void Main(string[] args)
{

    Person[] p = new Person[3];

    p[0] = new Person(8,"John", "Doe");
    p[1] = new Person(9,"Adam", "Cas");
    p[2] = new Person(1,"Oliver", "Anderson");

    Array.Sort(p,new Comparison<Person>((i1,i2)=> i1.Id.CompareTo(i2.Id)));   
}

what you can do also is to use Linq :

public  static void Main(string[] args)
{

    Person[] p = new Person[3];

    p[0] = new Person(8,"John", "Doe");
    p[1] = new Person(9,"Adam", "Cas");
    p[2] = new Person(1,"Oliver", "Anderson");

    var result = p.OrderBy(e => e.Id)
                 .ToArray(); 
}
sayah imad
  • 1,507
  • 3
  • 16
  • 24
  • Thanks, it helped me a lot, but i still seek a specific answer with hard coding to the mechanisms of comparing. It is an assignment needs to be solved with more details as my instructor requires. – Hardood May 10 '20 at 02:20
  • 1
    Our instructor wants us to create a new class eg:PersonComparer:IComparer with a constructor that receives a specific string property and then override the method Compare(Person x, Person y) with switch - case to determine the property which is going to be used on sorting. To perform sorting in the main method you will type Array.Sort(p, new PersonComparer("LastName")); That is what he did and it works perfectly. – Hardood May 10 '20 at 11:41
1

You can make Person implement IComparable<Person>, like this:

using System;
using System.Diagnostics.CodeAnalysis;

public class Person : IComparable<Person>
{
    private int _id;
    private string _firstName;
    private string _lastName;

    public Person(int id, string l, string f)
    {
        _firstName = f;
        _lastName = l;
        _id = id;
    }

    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    public int CompareTo(Person other)
    {
        return this.LastName.CompareTo(other.LastName);
    }
}

Then change the logic in CompareTo for whatever you want to compare. In this case, it does LastName, but you could also change that to ID or FirstName.

BTW, it looks like you have your first and last names backwards when instantiating and assigning Person to the p array.

Joe Mayo
  • 7,501
  • 7
  • 41
  • 60
  • Thanks for your answer. your solution is OK, but it just works for LastName, I want to give more options to be chosen on sorting, Like sorting by any one of my properties. – Hardood May 10 '20 at 02:01
1

You can use Comparison<T> delegate to sort the Person array by any property of this class

Comparison<Person> comparison = (x, y) => x.FirstName.CompareTo(y.FirstName);
Array.Sort(p, comparison);

Another (and more generic) way is to write an extension method for Person[] array and pass a Func<Person, TValue> selector to get a value, used for comparison during sort

public static class Ext
{
    public static void SortExt<TValue>(this Person[] array, Func<Person, TValue> selector)
    {
        var comparer = Comparer<TValue>.Default;
        Array.Sort(array, (x, y) => comparer.Compare(selector(x), selector(y)));
    }
}

Example of the usage

p.SortExt(person => person.FirstName); //or p.SortExt(person => person.LastName);
Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66