C#:按自定义属性对列表进行排序

3

很抱歉如果这是重复的,麻烦指出正确的问题。

我有一个叫做MyDate的类,代码如下:

public class MyDate
{
    private SqlDateTime m_dateTime;

    public MyDate(DateTime dateTime)
    {
       if (DateTime.Compare(dateTime, (DateTime)SqlDateTime.MinValue) <= 0)
            m_dateTime = SqlDateTime.MinValue;
        else
            m_dateTime = dateTime;
    }

    public string MMDDYYYYHHMMSS
    {
       get
         {
            if(m_dateTime > SqlDateTime.MinValue)
                return m_dateTime.Value.ToString("MM/dd/yyyy hh:mm:ss tt");
            else
                return String.Empty;
         }
    }
}

我有一个名为MyEvent的类,如下所示。
public class MyEvent
{
  public int EventId{get;set;}
  public MyDate StartDate{get;set;}
}

我有一个类似这样的MyEvent集合:

List<MyEvent> myEvents. 

现在我需要按StartDate的降序对myEvents进行排序。问题是,我无法添加IComparable或更改MyDate,因为它是由其他团队编写的,我只能引用dll。我无法控制MyDate代码。请问有人可以帮助我如何做到这一点?我创建了一个实现IComparer接口的新比较器类,但是无法理解如何使用它来对myEvents进行排序。

** 更新1 **

非常感谢Alexei、Ehsan和Dave的帮助。我尝试了Dave的答案,它有效了。我试图以更好的方式完成它,以便不需要添加任何新属性。我没有尝试Ehsan使用StringDateComparer的方法,但它帮助我理解了如何在Order linq语句中使用Comparer。最后,就像Alexei指出的那样,我做了如下操作

** 更新2 **

有时我会得到e2.StartDate.MMDDYYYYHHMMSS和/或e2.StartDate.MMDDYYYYHHMMSS的空字符串,所以我将我的代码更改如下

myEvents.Sort(
                delegate(MyEvent e1, MyEvent e2)
                 {
                     DateTime dt1;
                     DateTime dt2;
                     DateTime.TryParse(e1.StartDateTime.MMDDYYYYHHMMSS, out dt1);
                     DateTime.TryParse(e2.StartDateTime.MMDDYYYYHHMMSS, out dt2);

                     return dt2.CompareTo(dt1); // descending
                     //return dt1.CompareTo(dt2); // ascending
                    }
            );

请提供原始内容以进行翻译。 - Ehsan Sajjad
2
一个类,它接受一个 DateTime,将其转换为 SqlDateTime 并仅暴露一个 string?你真正的问题是与另一个团队相关的。 - juharr
你显然已经看到了我认为是你问题的重复,因为它首先链接到搜索你帖子标题的网页(https://www.bing.com/search?q=C%23+%3A+Sort+list+on+custom+property)。请澄清为什么那里提出的解决方案没有起作用(包括自定义比较器),以便清楚地表明这篇文章不是重复的。 - Alexei Levenkov
我的情况有所不同。在MyDate中,我没有任何DateTime属性。因此,我无法使用任何排序或按方法排序。我试图避免在MyEvent类中添加额外的属性。我尝试了IComparer。我看到的所有示例都直接跳过了使用OrderBy linq语句,而没有展示IComparer实现如何发挥作用... - Ziggler
@Ziggler 在 https://dev59.com/1nA75IYBdhLWcg3waIQJ#3309397 中展示了一个完美的自定义比较器的例子... - Alexei Levenkov
2个回答

3

这种方法可能不太高效,但你可以在你的 MyEvent 类中添加一个 DateTime 属性,将 StartDate 转换成 DateTime 并根据该属性进行排序:

public class MyEvent
{
    public int EventId{get;set;}
    public MyDate StartDate{get;set;}
    public DateTime MyStartDate { get { return DateTime.Parse(StartDate.MMDDYYYYHHMMSS); } }
}

var sorted = myEvents.OrderByDescending(e => e.MyStartDate);

或者,您可以使类成为不可变的,并在实例化时执行转换:

public class MyEvent
{
    public MyEvent(int eventId, MyDate startDate)
    {
        EventId = eventId;
        StartDate = startDate;
        MyStartDate = DateTime.Parse(StartDate.MMDDYYYYHHMMSS);
    }

    public int EventId{get; private set;}
    public MyDate StartDate{get; private set;}
    public DateTime MyStartDate { get; private set; }
}

1
更好的做法是在创建MyEvent时设置MyStartDate属性,并使MyEvent不可变。 - juharr
非常感谢。我尝试了一下,它起作用了。我试图以更好的方式来完成它,这样就不需要添加任何新属性。 - Ziggler

3
您可以根据需要使用 Linq 的 OrderyBy()OrderByDescending 方法进行编写,示例如下:
var outputDate = myEvents.OrderByDescending(x=>
                          {
                           DateTime parsedDate;
                           return DateTime.TryParseExact(x.StartDate, "MM/dd/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate) ? parsedDate : DateTime.MinValue;
                          });

或者更好的方法是为其创建一个自定义的IComparer

public class StringDateComparer : IComparer<string>
{

    public int Compare(string date1, string date2)
    {
        DateTime parsedDate1;
        DateTime.TryParseExact(date1, "MM/dd/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate1);


        DateTime parsedDate2;
        DateTime.TryParseExact(date2, "MM/dd/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate2);



        if (parsedDate1 < parsedDate2)
            return -1;
        if (parsedDate1 > parsedDate2)
            return 1;


        return 0;
    }
}

现在调用 OrderByDescending() 重载方法,该方法以 IComparer 对象作为参数:

var outputDate = myEvents.OrderByDescending(x=>x.StartDate,new StringDateComparer());

非常感谢。我还没有尝试过,但这帮助我理解了如何在Order linq语句中使用Comparer。 - Ziggler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接