【问题标题】:Different results LINQ vs 'normal' C# code不同的结果 LINQ 与“正常”C# 代码
【发布时间】:2015-12-10 21:47:06
【问题描述】:

我在这方面摸不着头脑。我认为下面的代码应该产生相同的结果。然而,他们没有。我显然错过了一些东西。 LINQ 查询返回一个比普通 C# 代码小的 long。

    public static long GetListSize(SPList list)
    {
        long longInt = 0;
        long byteSize = (from item in list.Items.OfType<SPListItem>()
                         where item.ParentList.EnableVersioning == false
                         select long.TryParse(item["File_x0020_Size"].ToString(), out longInt) ? longInt : 0)
                 .Concat(from iItem in list.Items.OfType<SPListItem>()
                         where iItem.ParentList.EnableVersioning == true && iItem.Versions.Count > 1
                         from vItem in iItem.Versions.OfType<SPListItemVersion>()
                         select long.TryParse(vItem["File_x0020_Size"].ToString(), out longInt) ? longInt : 0)
                 .Sum();

        return byteSize;
    }

    public static long GetListSize2(SPList list)
    {
        long byteSize = 0;
        long fileSize = 0;
        foreach (SPListItem item in list.Items)
        {
            if (item.ParentList.EnableVersioning == true && item.Versions.Count > 1)
            {
                for (int i = 0; i < item.Versions.Count; i++)
                {
                    long.TryParse(item.Versions[i]["File_x0020_Size"].ToString(), out fileSize);
                    byteSize += fileSize;
                }
            }
            else
            {
                long.TryParse(item["File_x0020_Size"].ToString(), out fileSize);
                byteSize += fileSize;
            }
        }
        return byteSize;
    }

当我针对同一个列表运行它们时:

GetListSizeForCurrentItems:2401408086
GetListSizeForCurrentItems2:2401408086
GetListSizeForItemVersions:459902667
GetListSizeForItemVersions2:459902667
获取列表大小:459902667
GetListSize2: 2842896668

重构代码以隔离上述每个查询:

    public static long GetListSizeForItemVersions(SPList list)
    {
        long longInt = 0;
        long byteSize = (from iItem in list.Items.OfType<SPListItem>()
                         where iItem.ParentList.EnableVersioning == true && iItem.Versions.Count > 1
                         from vItem in iItem.Versions.OfType<SPListItemVersion>()
                         select long.TryParse(vItem["File_x0020_Size"].ToString(), out longInt) ? longInt : 0)
                 .Sum();

        return byteSize;
    }
    public static long GetListSizeForItemVersions2(SPList list)
    {
        long byteSize = 0;
        long fileSize = 0;
        foreach (SPListItem item in list.Items)
        {
            if (item.ParentList.EnableVersioning == true && item.Versions.Count > 1)
            {
                for (int i = 0; i < item.Versions.Count; i++)
                {
                    long.TryParse(item.Versions[i]["File_x0020_Size"].ToString(), out fileSize);
                    byteSize += fileSize;
                }
            }
        }
        return byteSize;
    }

    public static long GetListSizeForCurrentItems(SPList list)
    {
        long longInt = 0;
        long byteSize = (from item in list.Items.OfType<SPListItem>()
                         where item.ParentList.EnableVersioning == false
                         select long.TryParse(item["File_x0020_Size"].ToString(), out longInt) ? longInt : 0)
                         .Sum();
        return byteSize;
    }
    public static long GetListSizeForCurrentItems2(SPList list)
    {
        long byteSize = 0;
        long fileSize = 0;
        foreach (SPListItem item in list.Items)
        {
            long.TryParse(item["File_x0020_Size"].ToString(), out fileSize);
            byteSize += fileSize;
        }
        return byteSize;

    }

对 Concat() 的更改肯定会改变结果。

多一双眼睛会有好处。在将普通的 C# 转换为 LINQ 时我缺少什么。

【问题讨论】:

  • 除了使用 Union 而不是 Concat 之外,您还在查询的第一部分中包含 EnableVersioning==false 值,而在您的普通 C# 代码中,您仅使用“else”让单个项目占总和的一个部分。
  • 嗨,乔恩,关于 else(和 Union/Concat),你是对的。但是,如果我使用 EnableVersioning == false 将 where 子句添加到查询的第一部分,我会得到相当大的结果差异。我将更新问题以反映现在正在发生的事情。
  • 请注意,如果您可以提供一个简短但 完整 的示例,并删除任何无关的内容(如字符串解析 - 您确定这是甚至需要?)
  • 对于一个项目 ParentList.EnableVersioning 是否有可能在版本数为 1 的情况下为真?如果是,那么 GetListSize2 会做错事。如果item.ParentList.EnableVersioning == false || item.Versions.Count &lt;= 1,则执行GetListSize2中的else部分。

标签: c# linq


【解决方案1】:

我猜问题出在Union。它返回......(强调我的)

一个IEnumerable&lt;T&gt;,包含来自两个输入序列的元素,不包括重复项

因此,如果您的列表中有重复项,则您只计算唯一值。请改用Concat

【讨论】:

  • 嗨,这确实提供了大部分数字为何关闭的答案。我仍然遇到总数不匹配的问题。我将更新问题以反映现在的情况。
  • 他总是这样 :) 。您只能接受答案,不能接受 cmets。
【解决方案2】:

在 GetListSize2() 中,您不检查 long.TryParse 是否返回 false。

TryParse 方法与 Parse 方法类似,只是 TryParse 方法在转换失败时不会抛出异常。它无需在 s 无效且无法成功的情况下使用异常处理来测试 FormatException已解析。

因此,如果您的列表中有一些非数字数据,则 fileSize 不会为 0,而是上一次迭代的文件大小。

更正如下:

public static long GetListSize2(SPList list)
{
    long byteSize = 0;
    long fileSize = 0;
    foreach (SPListItem item in list.Items)
    {
        if (item.ParentList.EnableVersioning == true && item.Versions.Count > 1)
        {
            for (int i = 0; i < item.Versions.Count; i++)
            {
                if (long.TryParse(item.Versions[i]["File_x0020_Size"].ToString(), out fileSize) == false)
                    fileSize=0;
                byteSize += fileSize;
            }
        }
        else
        {
            if (long.TryParse(item["File_x0020_Size"].ToString(), out fileSize) == false)
                    fileSize=0;
            long.TryParse(item["File_x0020_Size"].ToString(), out fileSize);
            byteSize += fileSize;
        }
    }
    return byteSize;
}

【讨论】:

  • 你确定吗? ` PS C:\Users\XXXX\Documents> [Int64]$i = 0 [Void][Int64]::TryParse("12", [ref]$i) $i [Void][Int64]::TryParse( "2", [ref]$i) $i [Void][Int64]::TryParse("c", [ref]$i) $i 12 2 0 ` Ughh...我无法格式化就像一个帖子...但是我在 PowerShell 中执行的示例在解析 alpha 时返回 0...
  • 在调用 TryParse 之后之前的值不可能通过。使用 out 参数的方法在返回之前是 required to assign a valueInt64.TryParse 的文档也明确指出,方法失败时该值为 0。
  • 对不起,你是对的。如果解析失败,则 TryParse 重新分配 0。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
相关资源
最近更新 更多