首页 > 解决方案 > 在任何访问(foreach 等)上自动对 List<> 中的元素执行特定操作

问题描述

基本描述和上下文:

从结构上讲,有一个数据库对象具有对象列表(基本上每个列表都是一个表),并且所述列表的每个成员都可以有自己的列表。

所有 XML 内容都在后台完成,因此编码人员不必担心这一点。

如果列表中的对象有自己的一个或多个列表,则在object.open()调用之前它们是空的(将数据从 XML 加载到内存)。

问题是导航这个结构。如果我可以调用类似GetLazilyInitializedXX()的方法会返回一个具有相同引用的新列表,但是当访问任何成员时它具有自动操作(但仅在那时。不是所有的,除非 foreach 真的经过所有这些,否则会很棒)例如!)。类似的东西LazyList<>

使用示例:我需要从结构的更深部分找到最新的yCount(代码中调用的)数据。amount列表从最早的记录日期到最新的排序。所以目前我必须创建一个顺序相反的新列表,在每个后续列表上使用 foreach 并手动调用.open()列表成员,并在yCount达到时返回选择。

如果列表中的对象在.open()从这样的“LazyList”中被访问/获取(以任何方式,即即使在 foreach 中,并且只有那些真正被“获取”的对象)时,则可以使用“select / where”(即使在foreach),简化了很多代码并删除了很多嵌套。

当前 WIP 代码(有大量嵌套):

/// <summary>
/// Gets the latest Daily Test Data.
/// </summary>
/// <param name="amount">The amount of Daily Tests to get</param>
/// <param name="fromDateTime">The date to get Daily Tests from (default - today)</param>
/// <returns></returns>
public static List<QCUnitDailyTestData> GetLatestDailyTestData(int amount = 1, DateTime? fromDateTime = null)
{
    List<QCUnitDailyTestData> result = new List<QCUnitDailyTestData>();

    //Removing the time from the date. If fromDateTime is null, using current DateTime
    var fromDate = fromDateTime?.Date ?? DateTime.Now.Date;

    Log.Info("Selecting " + amount + " latest Daily Tests from: " + fromDate); //todo format fromDate?

    //We need to go through years from the latest to oldest.
    foreach (ProductionYear productionYear in Database.GetProductionYearsFromLatest())
    {
        //LazyInit!
        productionYear.Open();

        //We need to go through days from the latest to oldest.
        foreach (ProductionDay productionDay in productionYear.GetProductionDaysFromLatest())
        {
            //LazyInit!
            productionDay.Open();

            //If the production day is before fromDate or it is the same day as fromDate...
            if (productionDay.Data.Date.Date.CompareTo(fromDate) < 1)
            {
                //We only want the newest daily test. The other ones (in the same day) aren't used!
                QCUnitDailyTest dailyTest = productionDay.GetDailyTestsFromLatest().FirstOrDefault();

                //A day doesn't have to have a daily test - if there is no daily test, continue with the next day
                if (dailyTest == null) continue;

                //LazyInit!
                dailyTest.Open();

                result.Add(dailyTest.Data); //Adding to the resulting list

                //If we have enough, we return the resulting list
                if (result.Count == amount)
                {
                    Log.Info("Selection completed successfully.");
                    return result;
                }
            }
        }
    }

    //if there are no Daily Tests matching our criteria, or there weren't enough of them, we return either an empty
    // list or those we found
    int count = result.Count;
    Log.Warn(count == 0 ? "No Daily Tests were found." : "Only " + count + " Daily Tests were found.");
    return result;
}

标签: c#

解决方案


我确实解决了它,但该解决方案非常特定于我们的“数据库”,主要问题是 - 如何在以任何方式访问所述元素时自动使用 List<> 元素执行操作。

数据控制器:

/// <summary>
/// Gets the latest Daily Test Data.
/// </summary>
/// <param name="amount">The amount of Daily Tests to get. Default - 1</param>
/// <param name="fromDateTime">The date to get Daily Tests from (default - today)</param>
/// <returns></returns>
public static List<QCUnitDailyTestData> GetLatestDailyTestData(int amount = 1, DateTime? fromDateTime = null)
{
    List<QCUnitDailyTestData> result = new List<QCUnitDailyTestData>();

    //Removing the time from the date. If fromDateTime is null, using current DateTime
    var fromDate = fromDateTime?.Date ?? DateTime.Now.Date;

    Log.Info("Selecting " + amount + " latest Daily Tests from: " + fromDate); //todo format fromDate?

    //We need to go through years, days and daily tests from the latest to oldest.
    foreach (var dailyTest in
        from productionYear in Database.GetProductionYearsFromLatest()
        from productionDay in productionYear.GetProductionDaysFromLatest()
            where productionDay.GetData().Date.Date.CompareTo(fromDate) < 1 //If the production day is before fromDate or it is the same day as fromDate...
        select productionDay.GetDailyTestsFromLatest().FirstOrDefault()//We only want the newest daily test. The other ones (in the same day) aren't used!
        into dailyTest where dailyTest != null /*A prod. day doesn't have to have a daily test*/ select dailyTest)
    {
        result.Add(dailyTest.GetData()); //Adding to the resulting list

     //If we have enough, we return the resulting list
     if (result.Count == amount)
     {
         Log.Info("Selection completed successfully.");
         return result;
     }
 }

        //if there are no Daily Tests matching our criteria, or there weren't enough of them, we return either an empty
        // list or those we found
        int count = result.Count;
        Log.Warn(count == 0 ? "No Daily Tests were found."
                            : "Only " + count + " Daily Tests were found.");
        return result;
    }

数据.生产年份:

    /// <summary>
    ///  <see cref="Days"/> lists <see cref="ProductionDay"/> instances.
    /// </summary>
    private readonly List<ProductionDay> Days = new List<ProductionDay>();

    /// <summary>
    /// For LazyInits - opens the year on access to days
    /// </summary>
    /// <returns></returns>
    public List<ProductionDay> GetDays()
    {
        if (!Opened) Open();
        return Days;
    }

    /// <summary>
    /// Returns A NEW INSTANCE of production days, with the order from latest to newest
    /// </summary>
    /// <returns>See summary</returns>
    public List<ProductionDay> GetProductionDaysFromLatest()
    {
        List<ProductionDay> days = new List<ProductionDay>(GetDays());
        days.Sort((day1, day2) => day1.GetDate(true).CompareTo(day2.GetDate(true)));
        return days;
    }

只是为了完整起见 Data.ProductionDay:

    private DateTime Date => Data.Date; //Nullpointer when the day isn't opened
    private DateTime DateLazy;

    /// <summary>
    /// If closed, return DataLazy instead of Data.Date, unless lazyStrict is false
    /// </summary>
    /// <returns>See summary</returns>
    public DateTime GetDate(bool lazyStrict = false)
    {
        if (!Opened && !lazyStrict)
        {
            Open();
            return Data.Date;
        }

        return Data?.Date ?? DateLazy;
    }

但正如我所说,这个解决方案非常适合我们的项目。

编辑:格式(括号......)也有点搞砸了。它们不在编码环境中(JetBrains Rider),所以我可能会把它们原封不动地保留在这里,带着它们所有的古怪荣耀。

EDIT2:此外,为年和日提供的代码不是整个课程,只有相关部分。


推荐阅读