为什么调用IEnumerable <string> .Count()会创建一个额外的程序集依赖项?</string>

时间:2011-01-06 09:48:45

标签: c# .net linq

假设这个dll链引用

Tests.dll >> Automation.dll >> White.Core.dll

在Tests.dll中使用以下代码行,其中所有内容都构建

result.MissingPaths 

现在我将其更改为

result.MissingPaths.Count()

我为Tests.dll收到以下构建错误“White.UIItem未在未引用的程序集中定义。您必须添加对White.Core.dll的引用。”我不想这样做,因为它打破了我的分层。

这是结果的类型定义,它位于Automation.dll

public class HasResult
        {
            public HasResult(IEnumerable<string> missingPaths )
            {   MissingPaths = missingPaths;           }

            public IEnumerable<string> MissingPaths { get; set; }

            public bool AllExist
            {
                get { return !MissingPaths.Any(); }
            }
        }

在调用链中,通过(TreeNode类在White.Core.dll中)创建此ctor的输入参数

assetPaths.Where(assetPath => !FindTreeNodeUsingCache(treeHandle, assetPath));

为什么在IEnumerable上调用Count()时这个依赖项会泄漏?然后我怀疑懒惰的评估导致了这个问题(出于某种原因) - 所以我在上面的行中插入了一个ToArray()但是没有用。

更新2011 01 07: Curiouser和Curiouser! 在添加White.Core引用之前,它不会构建。所以我添加一个引用并构建它(为了找到难以捉摸的依赖源)。在Reflector中打开它,列出的唯一引用是Automation,mscorlib,System.core和NUnit。所以编译器丢弃了White引用,因为它不需要。 ILDASM还确认没有White AssemblyRef条目。

关于如何深入了解这件事的任何想法(主要是'现在我想知道为什么'的原因)?这是VS2010 / MSBuild错误的可能性有多大?

更新2011 01 07#2 根据Shimmy的建议,尝试将explcitly方法称为扩展方法

Enumerable.Count(result.MissingPaths)

它停止了抄袭(不确定为什么) 但是之后我移动了一些代码,现在我使用IEnumerable在不同的位置获得相同的问题 - 这次是从磁盘上的文件读取和过滤行(完全与白色无关)。好像它是一个'症状修复' var lines = File.ReadLines(aFilePath).ToArray(); 再次,如果我删除ToArray()它再次编译 - 似乎导致可枚举的任何方法(ToArray,Count,ToList等)导致这种情况。让我尝试使用一个有效的小应用来演示这个问题......

更新2011 01 07#3 唷!更多信息..事实证明问题只在一个源文件中 - 这个文件是LINQ-phobic。必须显式调用对Enumerable扩展方法的任何调用。 我做的重构导致一个新的方法被移动到这个源文件,它有一些LINQ :)仍然没有线索为什么这个类不喜欢LINQ。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using G.S.OurAutomation.Constants;
using G.S.OurAutomation.Framework;
using NUnit.Framework;

namespace G.S.AcceptanceTests
{
    public abstract class ConfigureThingBase : OurTestFixture
    {
      ....
        private static IEnumerable<string> GetExpectedThingsFor(string param)
        {
                // even this won't compile - although it compiles fine in an adjoining source file in the same assembly
                //IEnumerable<string> s = new string[0];
                //Console.WriteLine(s.Count()); 



                // this is the line that is now causing a build failure   
            //  var expectedInfo = File.ReadLines(someCsvFilePath))
//                  .Where(line => !line.StartsWith("REM", StringComparison.InvariantCultureIgnoreCase))
//                  .Select(line => line.Replace("%PLACEHOLDER%", param))
//                  .ToArray();

                // Unrolling the LINQ above removes the build error

            var expectedInfo =
                Enumerable.ToArray(
                    Enumerable.Select(
                        Enumerable.Where(
                            File.ReadLines(someCsvFilePath)),
                            line => !line.StartsWith("REM", StringComparison.InvariantCultureIgnoreCase)),
                        line => line.Replace("%PLACEHOLDER%", param)));

更新2011 01 11#4 把它缩小到似乎是perp但没有动机:) 周末恢复了任务......并且使用常绿的消除过程,能够在违规位上划分。 问题是Tests.dll

中源文件中的以下using指令
using G.S.OurAutomation.Framework;

接下来,我追踪了这个命名空间中最可能的嫌疑人,并且我将WhiteExtensions置于聚光灯下。

namespace G.S.OurAutomation.Framework
{
   public static class WhiteExtensions
   {
        public static T PollAndGet<T>(this Window parentWindow, string automationId) where T : UIItem ...
        public static Window WaitForWindowWithTitle(this Application application, string windowTitle) ...
        public static bool HasTreeNode(this Tree treeHandle, string assetPath) ...
        public static HasTreeNodesResult HasTreeNodes(this Tree treeHandle, IEnumerable<string> assetPaths)...
   }
}

这导致了3个修复,两个都有效。

  1. 将扩展方法转换为普通的静态方法。
  2. 将此类移至子名称空间G.S.OurAutomation.Framework.White
  3. 将此作为一个内部类(因为它用于内部消费......再次选择限制性最强的访问修饰符的指导方针会让我感到厌烦。)
  4. 虽然我的具体实例已修复,但此更新是否可以帮助某人解释原因?如果没有,那么就可以指向正确的方向。[/ p>

3 个答案:

答案 0 :(得分:4)

尝试调用System.Linq.Enumerable.Count(result.MissingPaths)(带或不带完整的命名空间引用)。

Count是一种扩展方法,您可以明确地调用它。

Gishu更新后的更新#2:

所有内容的原因相同,函数ToArrayCountToList等都是System.Linq.Enumerable中声明的扩展方法。

BTW,重要:您是否仔细检查过命名空间System.Linq是否已导入(using System.Linq)到您的文件中?这甚至可以解决你所有的问题。

答案 1 :(得分:1)

编译器可能需要查看White.Core.dll以确定是否在您的类上定义了Count()方法。由于没有使用IEnumerable&lt;&gt;扩展方法的计数因此毕竟不需要White.Core.dll,但它不知道没有检查它。

但我无法解释IEnumerable<string>的情况如何,除非编译器检查你没有使用协方差?

答案 2 :(得分:0)

如何改变

public HasResult(IEnumerable<string> missingPaths )
{   MissingPaths = missingPaths;           }

public HasResult(IEnumerable<string> missingPaths )
{   MissingPaths = missingPaths.ToArray();           }

在使用结果的所有情况下,应该消除延迟加载方案。