Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何让Distinct()处理自定义对象的集合_C#_.net_Linq_Iequatable - Fatal编程技术网

C# 如何让Distinct()处理自定义对象的集合

C# 如何让Distinct()处理自定义对象的集合,c#,.net,linq,iequatable,C#,.net,Linq,Iequatable,我已经按照来自的建议尝试在我的代码中使用Distinct(),但仍然存在问题。以下是我正在使用的两个对象: public class InvoiceItem : IEqualityComparer<InvoiceItem> { public InvoiceItem(string userName, string invoiceNumber, string invoiceAmount) { this.UserNam

我已经按照来自的建议尝试在我的代码中使用Distinct(),但仍然存在问题。以下是我正在使用的两个对象:

    public class InvoiceItem : IEqualityComparer<InvoiceItem>
    {
        public InvoiceItem(string userName, string invoiceNumber, string invoiceAmount)
        {
            this.UserName = userName;
            this.InvoiceNumber= invoiceNumber;
            this.InvoiceAmount= invoiceAmount;
        }
        public string UserName { get; set; }
        public string InvoiceNumber { get; set; }
        public double InvoiceAmount { get; set; }

        public bool Equals(InvoiceItem left, InvoiceItem right)
        {
            if ((object)left.InvoiceNumber == null && (object)right.InvoiceNumber == null) { return true; }
            if ((object)left.InvoiceNumber == null || (object)right.InvoiceNumber == null) { return false; }
            return left.InvoiceNumber == right.InvoiceNumber;
        }


        public int GetHashCode(InvoiceItem item)
        {
            return item.InvoiceNumber == null ? 0 : item.InvoiceNumber.GetHashCode();
        }
    }


    public class InvoiceItems : List<InvoiceItem>{ }
当我设置代码并运行它时,我得到一个错误

无法将类型“System.Collections.Generic.IEnumerable”隐式转换为“InvoiceReader.Form1.InvoiceItems”。存在显式转换(是否缺少强制转换?)


我不知道如何解决这个问题。我应该采取不同的方法吗?非常感谢您的建议。

Distinct
返回一个通用的
IEnumerable
。它不返回
InvoiceItems
实例。事实上,在幕后,它返回一个代理对象,该代理对象实现了一个迭代器,该迭代器仅在需要时(即在您对其进行迭代时)才被访问

通过调用
.ToList()
,可以显式地将其强制到
列表中。不过,您仍然需要将其转换为自定义列表类型。最简单的方法可能是使用适当的构造函数,并调用:

public class InvoiceItems : List<InvoiceItem> {
    public InvoiceItems() { }

    // Copy constructor
    public InvoiceItems(IEnumerable<InvoiceItems> other) : base(other) { }
}

// …

InvoiceItems distinctItems = new InvoiceItems(aBunchOfInvoiceItems.Distinct());
公共类发票项:列表{
公共发票项(){}
//复制构造函数
公共发票项(IEnumerable other):基本(其他){}
}
// …
InvoiceItems differentitems=新的InvoiceItems(aBunchOfInvoiceItems.Distinct());

该错误与继承自
列表的类
InvoiceItems
有关


Distinct
返回一个
IEnumerable
InvoiceItems
是一种非常特殊的
IEnumerable
类型,但任何
IEnumerable
都不一定是
InvoiceItems

一个解决方案可能是使用隐式转换运算符,如果这是您想要做的:Doh,完全忘记您不能转换到接口或从接口转换(感谢Saed)

公共类发票项:列表
{
公共发票项(IEnumerable items):基本(items){}
}
其他需要注意的事项:

  • 列表继承通常是不好的。改为实施IList
  • 使用列表会丢掉LINQ的一大好处,即延迟评估。确保预取结果实际上是您想要做的

非常简单,
abunchofVoiceItems.Distinct()
返回一个
IEnumerable
,您试图将其分配给不是
IEnumerable
的对象

但是,
InvoiceItems
的基类有一个接受这样一个对象的构造函数,因此您可以使用它:

public class InvoiceItems : List<InvoiceItem>
{
  public InvoiceItems(IEnumerable<InvoiceItem> items)
    base(items){}
}
尽管如此,我认为从
List
中获得的好处不大,所以我可能更倾向于:

List<InvoiceItem> distinctItems = aBunchOfInvoiceItems.Distinct().ToList();
List differentitems=abunchofVoiceItems.Distinct().ToList();

Konrad Rudolph的回答应该可以解决编译问题。这里还有一个重要的语义正确性问题被忽略了:没有一个等式逻辑会被实际使用。

当比较器未提供给
Distinct
时,它使用
EqualityComparer.Default
。这将尝试使用
IEquatable
接口,如果缺少此接口,则使用在
object
上声明的普通的
Equals(object other)
方法。对于散列,它将使用
GetHashCode()
方法,该方法也在
object
上声明。由于您的类型尚未实现接口,并且上述方法都未被重写,因此存在一个大问题:
Distinct
将依赖于引用相等性,这不是您想要的

t当需要编写与类型本身解耦的相等比较器时,通常使用
IEqualityComparer
接口。另一方面,当一个类型希望能够将自己的实例与另一个实例进行比较时;它通常实现
IEquatable
。我建议:

  • 获取
    InvoiceItem
    以实现
    IEquatable
  • 将比较逻辑移动到一个单独的
    InvoiceItemComparer:IEqualityComparer
    类型,然后调用
    invoiceItems.Distinct(new InvoiceItemComparer())
  • 如果您想快速破解现有代码,可以执行
    invoiceItems.Distinct(newinvoiceitem())

  • 除了其他答案所处理的自定义类与IEnumerable的问题外,您的代码还有一个主要问题。您的类实现了
    IEqualityComparer
    ,而不是
    IEquatable
    。使用
    Distinct
    时,要筛选的项必须实现IEquatable本身,或者必须使用接受IEqualityComparer参数的重载。现在,对Distinct的调用将不会根据您提供的IEqualityComparer Equals和GetHashCode方法过滤项


    IEqualityComparer应该由被比较的类以外的另一个类实现。如果一个类知道如何比较自己,比如你的
    InvoiceItem
    类,它应该实现IEquatable。

    ooh如果你修复了它们,你的代码有太多的编译错误,你不能在接口上使用隐式操作符。。。
    public class InvoiceItems : List<InvoiceItem>
    {
      public InvoiceItems(IEnumerable<InvoiceItem> items)
        base(items){}
    }
    
    InvoiceItems distinctItems = new InvoiceItems(aBunchOfInvoiceItems.Distinct());
    
    List<InvoiceItem> distinctItems = aBunchOfInvoiceItems.Distinct().ToList();