【问题标题】:InvalidOperationException when try to sort an array of objects in c#尝试在 c# 中对对象数组进行排序时出现 InvalidOperationException
【发布时间】:2020-08-25 14:06:15
【问题描述】:

我的 c# 控制台应用程序上有这个类

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

在我的 Main 方法中,我有以下代码:

 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
      }

如果它是简单类型的数组,如字符串、整数、..等,我可以轻松使用Array.Sort(myarray),然后将其排序。但是当我使用Array.Sort(p) 时,我得到一个异常(InvalidOperationException)。

正如Array.Sort 上的文档所说,这确实是预期的异常

无效操作异常 数组中的一个或多个元素没有实现IComparable 接口。

不幸的是,所有示例都显示了如何为字符串实现IComparer,而我需要能够按对象(Id、FirstName、LastName)的字符串 property 进行排序。并且没有我的对象可能需要实施的IComparable 样本。

这是文档中的一个示例:

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

确实有IComparer 的样本(如Using IComparer for sorting),但它们显示IComparer<T>... 还有IComparable 的样本是相应的文档IComparable 但那是用于非字符串的温度属性。

【问题讨论】:

标签: c# .net sorting


【解决方案1】:

这个错误是有道理的,因为您正在尝试对一个复杂对象进行排序,如何将一个对象与另一个对象进行比较,您可以使用IComparable <T> 比较接口来比较两个对象,如代码如下:

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

你也可以使用 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(); 
}

【讨论】:

  • 谢谢,它对我帮助很大,但我仍然通过硬编码来寻找比较机制的具体答案。这是一项任务,需要按照我的导师的要求用更多细节来解决。
  • 我们的讲师希望我们创建一个新类,例如:PersonComparer:IComparer,其构造函数接收特定的字符串属性,然后用 switch 覆盖方法 Compare(Person x, Person y) - case 来确定将用于排序的属性。要在 main 方法中执行排序,您将键入 Array.Sort(p, new PersonComparer("LastName"));他就是这么做的,而且效果很好。
【解决方案2】:

你可以让Person实现IComparable&lt;Person&gt;,像这样:

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

然后将CompareTo 中的逻辑更改为您想要比较的任何内容。在这种情况下,它是LastName,但您也可以将其更改为IDFirstName

顺便说一句,在实例化 Person 并将其分配给 p 数组时,您的名字和姓氏似乎是倒序的。

【讨论】:

  • 感谢您的回答。您的解决方案没问题,但它只适用于姓氏,我想在排序时提供更多选项,比如按我的任何一个属性排序。
【解决方案3】:

您可以使用Comparison&lt;T&gt; 委托按此类的任何属性对Person 数组进行排序

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

另一种(更通用)的方法是为Person[]数组编写一个扩展方法,并传递一个Func&lt;Person, TValue&gt;选择器来获取一个值,用于排序时的比较

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

使用示例

p.SortExt(person => person.FirstName); //or p.SortExt(person => person.LastName);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-23
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 2021-11-18
    相关资源
    最近更新 更多