简体   繁体   English

C#-排序列表 <SomeClass> 通过使用自定义的CompareTo方法

[英]C# - sort List<SomeClass> by using custom CompareTo method

I have the following classes hierarchy: 我具有以下类层次结构:

abstract class Product : IComparable
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Barcode { get; set; }

    public int CompareTo(object obj)
    {
        int ret = -1;
        if (String.Compare(this.GetType().Name, obj.GetType().Name,StringComparison.Ordinal) == 0) 
            ret = 0;

        return ret;
    }
}

abstract class Book : Product
{
    public int PagesCount { get; set; }
}

class ProgrammingBook : Book
{
    public string ProgrammingLanguage { get; set; }
}

class CulinaryBook : Book
{
    public string MainIngridient { get; set; }
}

class EsotericBook : Book
{
    public int MininumAge { get; set; }
}
   abstract class Disc : Product
{
    internal enum Content
    {
        Music,
        Video,
        Software
    }

    public Content DiscContent { get; set; }
}

class CdDisc : Disc
{

}

class DvdDisc : Disc
{

}

And I trying to sort following collection by using IComparable interface method CompareTo: 我尝试使用IComparable接口方法CompareTo对以下集合进行排序:

 List<Product> products = new List<Product>
        {
            new DvdDisc {Name = "The lord of the rings 2",DiscContent = Disc.Content.Video,Price = 200M,Barcode = "5435443-2"},
            new CdDisc {Name = "Antonio Vivaldi: best picks",Price = 700M, DiscContent = Disc.Content.Music,Barcode = "4543765-565"},
            new CulinaryBook{Name = "Midterranian foods",MainIngridient = "Salmon",PagesCount = 436,Price = 350M,Barcode = "41457561-897"},
            new CdDisc{Name = "Windows XP", DiscContent = Disc.Content.Software, Price = 950M, Barcode = "5433668-4"},
            new EsotericBook{Name = "Russian Freemasonry 1731-2000",MininumAge = 21,PagesCount = 2100,Price = 3000M,Barcode = "6464632-876"},
            new CdDisc {Name = "The best of Mussorgsky",Price = 300M, DiscContent = Disc.Content.Music,Barcode = "5435436-567"},
            new ProgrammingBook{Name = "CLR via C#",PagesCount = 900, Price = 1110M,ProgrammingLanguage = "C#",Barcode = "5546533-2446"},
            new DvdDisc {Name = "The lord of the rings 1",DiscContent = Disc.Content.Video,Price = 200M,Barcode = "54354423-2"},
            new ProgrammingBook{Name = "ASP.NET MVC 4",PagesCount = 800,Price = 1200M,ProgrammingLanguage = "C#",Barcode = "46476573-65"},
            new EsotericBook{Name = "Russian Freemasonry in it's future and past",MininumAge =19, PagesCount = 900, Price = 2342M,Barcode = "3656353-24"},
            new CulinaryBook{Name = "Traditional Polish dishes",MainIngridient = "Red meat",PagesCount = 630,Price = 840,Barcode = "54634234-5"}
        }; products.Sort();

Output list should look like this: 输出列表应如下所示:

1.1 Programming books 1.1编程书籍
1.2 Culinary books 1.2烹饪书
1.3 Esoteric books 1.3神秘的书

2.1 Cd discs sorted by content 2.1 CD光盘按内容排序
2.2 DVD discs sorted by content 2.2 DVD光盘按内容排序

My current CompareTo method does only part of the job - comparing classes by name. 我当前的CompareTo方法仅完成部分工作-按名称比较类。

You need to work with equals option 您需要使用equals选项

rtn = Primary Sort;
if(rtn =0)
    rtn =secondary Sort;
if(rtn =0)
    rtn =tertiary Sort;

as your primary sort seems to be on the type of book 因为您的主要类型似乎是书籍类型

you would do 你会做

rtn = this.GetType().Name.CompareTo(obj.GetType().Name);
if(rtn ==0)
    rtn =this.Name.CompareTo(obj.Name);
return rtn;

if your problem is that you don't want alphabetic sorting on the type then add to product 如果您的问题是您不想按字母顺序对类型进行排序,则将其添加到产品中

public abstract int SortOrder{get;}

and use that as your primary sort 并以此作为您的主要排序

This is a working example that will render the exact same output: 这是一个工作示例,将呈现完全相同的输出:

1.1 Programming books 
1.2 Culinary books 
1.3 Esoteric books 

2.1 Cd discs sorted by content 
2.2 DVD discs sorted by content 

在此处输入图片说明

I also added IComparable<Product> to more easily make it comparable with other products. 我还添加了IComparable<Product>以便更轻松地使其与其他产品具有可比性。

 abstract class Product : IComparable<Product>
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Barcode { get; set; }
        protected abstract int InternalSortOrder { get; }
        protected virtual string SortBy { get {return Name;} }


        public int CompareTo(Product obj)
        {
            var sameType = string.Compare(GetType().Name, obj.GetType().Name, StringComparison.Ordinal) == 0;

            var sameBaseType = GetType().BaseType != null && obj.GetType().BaseType != null &&
                               string.Compare(GetType().BaseType.ToString(), obj.GetType().BaseType.ToString(),
                                   StringComparison.Ordinal) == 0;


            // They have the same base type, but not the same type. Order by base type first.
            if (!sameType && !sameBaseType && GetType().BaseType != null && obj.GetType().BaseType != null)
            {
                // Order by base type first.
                return string.Compare(GetType().BaseType.ToString(), obj.GetType().BaseType.ToString(),
                    StringComparison.Ordinal);
            }

            // it's the same base type (eg. book or disc)
            if (sameBaseType)
            {
                // Order by sort order.
                if (obj.InternalSortOrder != this.InternalSortOrder)
                {
                    return InternalSortOrder.CompareTo(obj.InternalSortOrder);
                }
            }

            if (sameType)
            {
                // Same sort order. We sort by name.
                return string.Compare(SortBy, obj.SortBy, StringComparison.Ordinal);
            }

            // Order by Type.
            return string.Compare(GetType().Name, obj.GetType().Name, StringComparison.Ordinal);
        }

    }

    abstract class Book : Product
    {
        public int PagesCount { get; set; }
    }

    class ProgrammingBook : Book
    {
        public string ProgrammingLanguage { get; set; }

        protected override int InternalSortOrder
        {
            get { return 1; }
        }
    }

    class CulinaryBook : Book
    {
        public string MainIngridient { get; set; }

        protected override int InternalSortOrder
        {
            get { return 2; }
        }
    }

    class EsotericBook : Book
    {
        public int MininumAge { get; set; }

        protected override int InternalSortOrder
        {
            get { return 3; }
        }
    }
    abstract class Disc : Product
    {
        internal enum Content
        {
            Music,
            Video,
            Software
        }

        protected override string SortBy
        {
            get { return DiscContent.ToString(); }
        }

        public Content DiscContent { get; set; }
    }

    class CdDisc : Disc
    {
        protected override int InternalSortOrder
        {
            get { return 1; }
        }
    }

    class DvdDisc : Disc
    {
        protected override int InternalSortOrder
        {
            get { return 2; }
        }
    }

UPDATE: 更新:

I've added virtual SortBy in Product . 我在Product添加了virtual SortBy It will go to Name by default, but Disc will return Content . 默认情况下它将转到Name ,但是Disc会返回Content

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM