LINQ问题 - 必须添加对不需要的库的引用

emp*_*mpi 13 c# linq compiler-construction extension-methods visual-studio

我有以下问题.我有一个包含大约40个项目的解决方案.有一个项目A引用了引用项目C的项目B.项目A中没有任何代码使用项目C中的类.但是,如果我在任何代码中使用任何LINQ扩展方法,例如:

var r = new int[] { 1, 2, 3 }.Where(a => a > 1);
Run Code Online (Sandbox Code Playgroud)

我收到编译器错误:

somefile.cs(70,13):错误CS0012:类型"XXX"在未引用的程序集中定义.您必须添加对程序集'Project C程序集名称,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = xxx'的引用.

错误在使用linq扩展方法的行上.

我正在使用VS2010,.NET 3.5.

更新:每种扩展方法都会发生这种情况.我在同一个文件中创建了一个类,如下所示:

public static class SomeClass
{
    public static int[] Test(this int[] a)
    {
        return a;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我写这个代码和编译中断同样的错误:

new int[] { 1, 2, 3 }.Test();
Run Code Online (Sandbox Code Playgroud)

Update2:好的,我发现了导致错误的原因.但我不知道为什么.以下代码导致错误:

using System.Linq;
using B;

namespace TestApp
{
    public class A
    {
        public void M()
        {
            var c = new string[] { "a", "b", "c" }.Where(s => s != null);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如果我使用B删除(我是按照我的描述中的名称,A引用B,B引用C),它就会编译.这是项目A中的唯一代码.如果我删除扩展方法的使用或者如前所述删除"使用B",则编译它.

UPDATE3:

首先,感谢您的所有建议.我能想出的最小例子如下.我创建了一个新项目,csproj看起来像这样(没有任何改变,只有C项目名称和C项目guid):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{B649AB2C-926A-4AD1-B7E3-5A29AE1E9CC2}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>ClassLibraryTest</RootNamespace>
    <AssemblyName>ClassLibraryTest</AssemblyName>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\C.csproj">
      <Project>{55AFFA2D-63E0-4BA9-XXXX-B70E6A936F5E}</Project>
      <Name>C</Name>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="Properties\" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Run Code Online (Sandbox Code Playgroud)

Class1.cs包含以下代码:

using C;

namespace TestApp
{
    public static class Ext
    {
        public static void M213dsacxvz(this string[] a)
        {
        }
    }

    public class A
    {
        public void B()
        {
            new string[] { "a", "b", "c" }.M213dsacxvz();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的编译器错误如下:

D:\ xxx\Class1.cs(16,13):错误CS0012:类型"xxx"在未引用的程序集中定义.您必须添加对程序集'xxx,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = xxx'的引用.

如果我删除using C;它编译就好了.

在此先感谢您的帮助.

Ric*_*key 9

这是一个重现问题的小例子.它是由B中的扩展方法引起的,该方法在其签名中使用C中定义的类型.即使未使用扩展方法,也会通过搜索可通过using访问的所有扩展方法的过程来触发错误.

ConsoleApplicationA.cs:

using ClassLibraryB;

namespace ConsoleApplication1
{
    public static class Extensions
    {
        public static int Test(this int a)
        {
            return a;
        }
    }

    public class ProgramA
    {
        static void Main(string[] args)
        {
            0.Test();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ClassLibraryB.cs:

using ClassLibraryC;

namespace ClassLibraryB
{
    public static class Extensions
    {
        public static ClassC Test(this ClassB b)
        {
            return new ClassC();
        }
    }

    public class ClassB
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

ClassLibraryC.cs:

namespace ClassLibraryC
{
    public class ClassC
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

此测试用例会产生此错误:

错误CS0012:类型'ClassLibraryC.ClassC'在未引用的程序集中定义.您必须添加对程序集"ClassLibraryC,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null"的引用.

编辑:

在我看来,这是C#编译器中的一个错误,因为对于你没有引用的方法来说,它的行为非常令人惊讶,导致程序无法编译.C#编译器团队可能有不同的意见.

与此同时,一种解决方法是将扩展方法放在B中,将其签名中的C类型用于单独的命名空间,并仅在调用程序集同时引用B和C时才向该命名空间添加using.违规扩展方法的数量很少,其价值有限,您可以移动或删除它们.最后,最明显的是,你可以完成它并简单地添加它告诉你应该添加的C的引用.

第二次编辑:

警告:我刚刚审查了这个以清理示例,它比我想象的要弱.只有当A中被调用的扩展方法的名称与B中未调用的扩展方法的名称完全匹配时,它才会失败.例如,如果你Test在B中重命名NotCalled它不再失败,但在原始问题中,可能它会.

最终编辑:

通过协作,我们缩小了重现原始问题中描述的问题的必要条件:B中的扩展方法,其签名中的C类型使用泛型类型约束.上述测试用例是一个较窄的例子.具体条件显然与编译器搜索扩展方法的具体实现有关.

总之,引用是运行时功能,扩展方法是编译时功能.无论如何生成错误消息,如果未调用该方法,编译器是在编译时需要引用的编译器,程序集在运行时不需要引用.因此,错误不是编译器除了发射之外别无选择的错误,这对编译器来说只是一个不方便的情况.


emp*_*mpi 2

我找到了解决方案。

您可以从此链接下载整个解决方案(相对于 2010 年):https://rapidshare.com/files/4269394110/ExtensionProblem.zip

感谢@Rick Sladkey,我找到了完整的答案,他的答案几乎是完整的。导致代码始终无法编译的唯一原因是项目 B 中使用项目 C 中的类指定的泛型方法的约束。

好的,这是清单:

项目A

A类.cs

using B;

namespace A
{
    public class ClassA
    {
        public void Foo()
        {
            new int[] { 1, 2, 3 }.ExtMethodC();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想让代码编译注释第一行( using B;)。

这是项目 A 中包含随机扩展方法的类。

扩展A.cs

namespace A
{
    public static class ExtensionsA
    {
        public static void ExtMethodC(this int[] a)
        {

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

项目B

Extensions.cs - 此类具有具有通用约束的方法T : ClassC

using C;

namespace B
{
    public static class Extensions
    {
        public static string ExtMethodB<T>(this T cInstance) where T : ClassC
        {
            return cInstance.Foo;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

项目C

ClassC.cs - 我们需要这个类在项目 B 的扩展方法中使用它

namespace C
{
    public class ClassC
    {
        public string Foo;
    }
}
Run Code Online (Sandbox Code Playgroud)

对我来说,这看起来像是编译器中的一个错误,它太急于检查项目 B 中的扩展方法是否可以在项目 A 中使用。

感谢您的所有回答!特别是@Rick Sladkey。