C# 如何使用可选属性顺序按对象中的属性对列表进行排序
假设我有一个基类和两个派生类C# 如何使用可选属性顺序按对象中的属性对列表进行排序,c#,list,sorting,generics,C#,List,Sorting,Generics,假设我有一个基类和两个派生类 public abstract class BaseClass { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } public string Owner { get; set; } public DateTime DateAdded { get; set; } }
public abstract class BaseClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
public class Foo : BaseClass
{
[CustomAttr(Order = 2)]
public string Country { get; set; }
[CustomAttr(Order = 5)]
public decimal Amount { get; set; }
public string Other { get; set; }
}
public class Bar : BaseClass
{
[CustomAttr(Order = 3)]
public string Organization { get; set; }
[CustomAttr(Order = 1)]
public string Keywords { get; set; }
}
默认情况下,属性的顺序取决于它们在类中的声明方式,因此如果在基类中,因为没有[CustomAttrOrder=n],则假定这是正确的顺序
现在,由于在两个派生类中,定义了一个自定义属性,该属性将标识行为应按以下顺序排序的属性顺序:
身份证件
国
名称
描述
数量
物主
添加日期
另外
因此,那些具有CustomAttr[Order=n]的属性应该按其属性顺序排列,对于那些没有的属性,我们假设它们的顺序正确。如果我使用Bar类,这也应该有类似的行为
这个用例是我需要在列表中具有正确的类属性顺序,才能在excel文件中具有正确的列顺序
我所做的是,我必须将CustomAttr[Order=n]添加到所有属性中以对它们进行排序,但是这是一件乏味的事情,如果您尝试更改其中一个属性顺序,则需要更改所有属性的顺序
有什么方法可以实现这一点吗?请参阅此示例,了解如何在system.Linq中使用列表进行订购
class Program
{
class test
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
static void Main(string[] args)
{
List<test> listOrder = new List<test>();
listOrder.Add(new test() { Id = 1, Name = "john", Description = "test", Owner = "test", DateAdded = DateTime.Now });
listOrder.Add(new test() { Id = 1, Name = "max", Description = "test1", Owner = "test1", DateAdded = DateTime.Now });
listOrder.Add(new test() { Id = 1, Name = "phil", Description = "test2", Owner = "test2", DateAdded = DateTime.Now });
List<test> sortbyName = listOrder.OrderBy(item => item.Name).ToList();
List<test> sortbyDescription = listOrder.OrderBy(item => item.Description).ToList();
List<test> sortbyOwner = listOrder.OrderBy(item => item.Owner).ToList();
}
}
您可以使用反射按声明的顺序读取类的所有属性的名称。然后您可以在逻辑中对此进行详细说明,并相应地对字段进行排序 请尝试以下操作:
PropertyInfo[] propertyInfos = typeof(Bar).GetProperties();
foreach (var propInfo in propertyInfos)
Console.WriteLine(propInfo.Name);
这将写入Bar类中的所有属性这只是一个示例,您可以用任何类替换它,包括从其超类基类继承的属性。预期输出:
Organization
Keywords
Id
Name
Description
Owner
DateAdded
请注意,该方法首先列出类中的属性,然后在层次结构中列出每个超类,这就是为什么Bar的成员在基类的成员之前列出的原因。您可以根据需要对代码进行详细说明,以更改顺序
下面的非优化代码首先创建给定类的所有层次结构的列表,从基类到给定的T类。然后,它迭代每个类,只发现在每个类中定义的属性。我将向GetProperties方法传递一个参数,说明我只需要是公共的、实例/非静态的,并且在我当前咨询的特定类上声明
预期输出将是按以下顺序排列的属性:
Id
Name
Description
Owner
DateAdded
Organization
Keywords
通过CustomAttr属性,您可以了解字段的声明顺序及其自定义顺序。现在,您可以实现一种排序方法,根据您的需要,根据字段的声明顺序和CustomAttr顺序对字段进行排序
但我想这超出了我的回答的范围,我的回答旨在向您展示如何获得属性声明的顺序,从基类到任何给定的特定类。我创建了一个通用解决方案,通过读取您的属性并创建一个比较器,将按照属性顺序进行比较我正在读比较器的反射属性。在比较时,我一个接一个地取一个属性,当等于零时,我转到下一个属性。 该逻辑还与继承一起工作,因此即使在基类上,也可以使用CustomAttr
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public class CustomAttr : Attribute
{
public CustomAttr():base()
{}
public CustomAttr(int Order)
{
this.Order = Order;
}
public int Order {get ; set ; }
}
public abstract class BaseClass
{
public int Id { get; set; }
[CustomAttr(Order = 20)]
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
public class Foo : BaseClass
{
[CustomAttr(Order = 2)]
public string Country { get; set; }
[CustomAttr(Order = 5)]
public decimal Amount { get; set; }
public string Other { get; set; }
}
public class Bar : BaseClass
{
[CustomAttr(Order = 3)]
public string Organization { get; set; }
[CustomAttr(Order = 1)]
public string Keywords { get; set; }
}
class app
{
static void Main()
{
List<Bar> listToOrder = new List<Bar>();
listToOrder.Add(new Bar() { Id = 5, Keywords = "Hello", Organization = "Arlando" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" , Name = "Deep"});
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta", Name = "Inherit" });
listToOrder.Add(new Bar() { Id = 1, Keywords = "Muppet", Organization = "Coke" });
listToOrder.Add(new Bar() { Id = 6, Keywords = "Grumpy", Organization = "Snow" });
listToOrder.Add(new Bar() { Id = 9, Keywords = "Johny", Organization = "White" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Bruno" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" });
listToOrder.Add(new Bar() { Id = 7, Keywords = "Set", Organization = "Voltra" });
listToOrder.Add(new Bar() { Id = 45, Keywords = "Brr", Organization = "Elvis" });
listToOrder.Add(new Bar() { Id = 15, Keywords = "Tsss", Organization = "Marion" });
OrderComparer<Bar> myOrder = new OrderComparer<Bar>();
listToOrder.Sort(myOrder);
foreach (Bar oneBar in listToOrder)
{
Console.WriteLine(oneBar.Id + " " + oneBar.Keywords + " " + oneBar.Organization);
}
Console.ReadKey();
}
private class OrderComparer<T> : IComparer<T>
{
SortedList<int, PropertyInfo> sortOrder = new SortedList<int, PropertyInfo>();
public OrderComparer()
{
Type objType = typeof(T);
foreach (PropertyInfo oneProp in objType.GetProperties())
{
CustomAttr customOrder = (CustomAttr) oneProp.GetCustomAttribute(typeof(CustomAttr), true);
if (customOrder == null) continue;
sortOrder.Add(customOrder.Order, oneProp);
}
}
public int Compare(T x, T y)
{
Type objType = typeof(T);
int result = 0;
int i = 0;
while (result == 0 && i < sortOrder.Count)
{
result = ((IComparable)sortOrder.ElementAt(i).Value.GetValue(x)).CompareTo(sortOrder.ElementAt(i).Value.GetValue(y));
i++;
}
return result;
}
}
}
你可以发布CustomAttr的代码,因为它看起来与你的问题相关。另外,如果没有指定,你必须在那里写一些逻辑来“假设”默认顺序。
Id
Name
Description
Owner
DateAdded
Organization
Keywords
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public class CustomAttr : Attribute
{
public CustomAttr():base()
{}
public CustomAttr(int Order)
{
this.Order = Order;
}
public int Order {get ; set ; }
}
public abstract class BaseClass
{
public int Id { get; set; }
[CustomAttr(Order = 20)]
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
public class Foo : BaseClass
{
[CustomAttr(Order = 2)]
public string Country { get; set; }
[CustomAttr(Order = 5)]
public decimal Amount { get; set; }
public string Other { get; set; }
}
public class Bar : BaseClass
{
[CustomAttr(Order = 3)]
public string Organization { get; set; }
[CustomAttr(Order = 1)]
public string Keywords { get; set; }
}
class app
{
static void Main()
{
List<Bar> listToOrder = new List<Bar>();
listToOrder.Add(new Bar() { Id = 5, Keywords = "Hello", Organization = "Arlando" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" , Name = "Deep"});
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta", Name = "Inherit" });
listToOrder.Add(new Bar() { Id = 1, Keywords = "Muppet", Organization = "Coke" });
listToOrder.Add(new Bar() { Id = 6, Keywords = "Grumpy", Organization = "Snow" });
listToOrder.Add(new Bar() { Id = 9, Keywords = "Johny", Organization = "White" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Bruno" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" });
listToOrder.Add(new Bar() { Id = 7, Keywords = "Set", Organization = "Voltra" });
listToOrder.Add(new Bar() { Id = 45, Keywords = "Brr", Organization = "Elvis" });
listToOrder.Add(new Bar() { Id = 15, Keywords = "Tsss", Organization = "Marion" });
OrderComparer<Bar> myOrder = new OrderComparer<Bar>();
listToOrder.Sort(myOrder);
foreach (Bar oneBar in listToOrder)
{
Console.WriteLine(oneBar.Id + " " + oneBar.Keywords + " " + oneBar.Organization);
}
Console.ReadKey();
}
private class OrderComparer<T> : IComparer<T>
{
SortedList<int, PropertyInfo> sortOrder = new SortedList<int, PropertyInfo>();
public OrderComparer()
{
Type objType = typeof(T);
foreach (PropertyInfo oneProp in objType.GetProperties())
{
CustomAttr customOrder = (CustomAttr) oneProp.GetCustomAttribute(typeof(CustomAttr), true);
if (customOrder == null) continue;
sortOrder.Add(customOrder.Order, oneProp);
}
}
public int Compare(T x, T y)
{
Type objType = typeof(T);
int result = 0;
int i = 0;
while (result == 0 && i < sortOrder.Count)
{
result = ((IComparable)sortOrder.ElementAt(i).Value.GetValue(x)).CompareTo(sortOrder.ElementAt(i).Value.GetValue(y));
i++;
}
return result;
}
}
}