LINQ 问题 - 需要添加对不需要的库的引用
我有以下问题。我有一个包含大约 40 个项目的解决方案。 有一个项目 A 引用了项目 B,而项目 B 又引用了项目 C。项目 A 中没有任何代码使用项目 C 中的类。但是,如果我在任何代码中使用任何 LINQ 扩展方法,例如:
var r = new int[] { 1, 2, 3 }.Where(a => a > 1);
我会收到编译器错误:
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;
}
}
然后我编写了此代码,编译因相同的错误而中断:
new int[] { 1, 2, 3 }.Test();
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);
}
}
}
但是如果我删除 using B (我仍然遵循我的描述中的名称,A 引用 B,B 引用 C),它会编译。 这是项目 A 中唯一的代码。如果我删除扩展方法的使用或者删除“使用 B”(如我之前所说),它就会编译。
更新3:
首先,感谢您的所有建议。 我能想到的最小的例子如下。我创建了一个新项目,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>
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();
}
}
}
我得到的编译器错误如下:
D:\xxx\Class1.cs(16,13):错误 CS0012:类型“xxx”在未引用的程序集中定义。您必须添加对程序集“xxx,Version=0.0.0.0,Culture=neutral,PublicKeyToken=xxx”的引用。
如果我删除 using C;
它编译得很好。
预先感谢您的帮助。
I have a following issue. I have a solution that contains about 40 projects.
There is a project A that references project B that references project C. There isn't any code in project A that uses classes from project C. However, if I use any LINQ extension method in any code, e.g.:
var r = new int[] { 1, 2, 3 }.Where(a => a > 1);
I get compiler error:
somefile.cs(70,13): error CS0012: The type 'XXX' is defined in an assembly that is not referenced. You must add a reference to assembly 'Project C assembly name, Version=0.0.0.0, Culture=neutral, PublicKeyToken=xxx'.
The error is on the line that uses linq extension method.
I'm using VS2010, .NET 3.5.
Update: It happens with every extension method. I have created a class in the same file, that looks like this:
public static class SomeClass
{
public static int[] Test(this int[] a)
{
return a;
}
}
And then I write this code and compilation breaks with same error:
new int[] { 1, 2, 3 }.Test();
Update2: Ok, I found out what causes the error. But I don't know why. Following code causes error:
using System.Linq;
using B;
namespace TestApp
{
public class A
{
public void M()
{
var c = new string[] { "a", "b", "c" }.Where(s => s != null);
}
}
}
But if I remove using B (I'm stil following the names from my description that A references B, B references C) it compiles.
This is the ONLY code in project A. It compiles if I remove usage of extension method or if I remove "using B" as I said before.
Update3:
First of all, thanks for all your suggestions.
The smallest example I can come up with is the following. I created a new project, csproj looks like this (nothing has been changed, only C project name and C project 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>
Class1.cs contains following code:
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();
}
}
}
The compiler error I get is as follows:
D:\xxx\Class1.cs(16,13): error CS0012: The type 'xxx' is defined in an assembly that is not referenced. You must add a reference to assembly 'xxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=xxx'.
If I remove using C;
it compiles just fine.
Thanks in advance for help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个重现该问题的小示例。它是由 B 中的扩展方法在其签名中使用 C 中定义的类型引起的。即使未使用扩展方法,该错误也会在搜索所有可通过 using 访问的扩展方法的过程中触发。
ConsoleApplicationA.cs:
ClassLibraryB.cs:
ClassLibraryC.cs:
此测试用例产生以下错误:
编辑:
在我看来,这是 C# 编译器中的一个错误,因为对于您未引用的方法,它的行为非常令人惊讶,导致程序无法编译。 C# 编译器团队可能有不同的意见。
同时,一种解决方法是将 B 中的扩展方法放置在其签名中使用 C 中的类型的扩展方法到单独的命名空间中,并且仅当调用程序集同时引用 B 和 C 时才将 using 添加到该命名空间。有问题的扩展方法的数量很少,并且它们的价值有限,您可以移动或删除它们。最后,也是最明显的,您可以完成它,只需添加它告诉您应该添加的对 C 的引用即可。
第二次编辑:
警告:我刚刚回顾了这个例子来清理这个例子,它比我想象的要弱。仅当 A 中被调用的扩展方法的名称与 B 中未调用的扩展方法的名称完全匹配时,它才会失败。例如,如果将 B 中的
Test
重命名为NotCalled
它不再失败,但在最初的问题中,大概会失败。最终编辑:
通过协作,我们缩小了重现原始问题中描述的问题的必要条件:B 中的扩展方法,其签名中的类型来自 C,使用泛型类型约束。上面的测试用例是一个更狭窄的示例。具体条件显然与编译器搜索扩展方法的具体实现方式有关。
总之,引用是运行时功能,扩展方法是编译时功能。无论错误消息如何生成,如果未调用该方法,编译器就是需要在编译时引用的人,而程序集不需要在运行时引用。因此,该错误并不是编译器别无选择只能发出的错误,这只是编译器的一种不方便的情况。
Here is a small example that reproduces the problem. It is caused by an extension method in B that uses types defined in C in its signature. Even though the extension method is not used, the error is triggered by the process of searching all extension methods that are accessible via usings.
ConsoleApplicationA.cs:
ClassLibraryB.cs:
ClassLibraryC.cs:
This test case produces this error:
Edit:
In my opinion, this is a bug in the C# compiler, because it very surprising behavior for a method you did not reference to cause your program to fail to compile. The C# compiler team may have a different opinion.
In the meantime, a workaround is to place your extension methods in B that use types from C in their signature into a separate namespace and add a using to that namespace only when the calling assembly has a reference to both B and C. Alternatively if the number of offending extension methods is small and their value is limited you might be able to move or remove them. Finally, and most obviously, you can be done with it and simply add the reference to C that it tells you you should add.
Second edit:
Caveat: I just reviewed this to clean up the example and it is weaker than I had thought. It only fails if the name of the called extension method in A exactly matches the name of the uncalled extension method in B. So for example if you rename
Test
in B toNotCalled
it no longer fails, yet in the original problem, presumably it would.Final edit:
With collaboration we narrowed down the necessary conditions to reproduce the issue described in the original question: an extension method in B with types from C in its signature that use a generic type constraint. The above test case is a narrower example. The specific conditions are clearly related to the specific implementation of the way the compiler searches for extension methods.
In summary, references are a run-time feature and extension methods are a compile-time feature. No matter how the error message is generated, if the method is not called, the compiler is the one who desires the reference at compile-time, the assembly does not need the reference at run-time. Therefore the error is not one that the compiler has no choice but the emit, it's just an inconvenient situation for the compiler.
我找到了解决方案。
您可以从此链接下载整个解决方案(相对于 2010):https://rapidshare.com/files /4269394110/ExtensionProblem.zip。
感谢@Rick Sladkey,我找到了完整的答案,他的答案几乎是完整的。导致代码始终无法编译的唯一原因是项目 B 中使用项目 C 中的类指定的泛型方法的约束。
好的,这里是清单:
PROJECT A
ClassA.cs
如果您希望代码编译注释第一行(
using B;
)。这是一个在项目 A 中包含随机扩展方法的类。
ExtensionsA.cs
PROJECT B
Extensions.cs - 该类具有带有通用约束
T : ClassC
PROJECT 的方法CClassC.cs
- 我们需要这个类在项目 B 的扩展方法中使用
它对我来说,它看起来像是编译器中的一个错误,它太急于检查项目 B 中的扩展方法是否可以在项目 A 中使用。
感谢您的所有回答!特别是@Rick Sladkey。
I found the solution.
You may download the whole solution (vs 2010) from this link: https://rapidshare.com/files/4269394110/ExtensionProblem.zip.
I found the complete answer thanks to @Rick Sladkey whose answer was almost complete. The only thing that causes the code to always fail to compile is a constraint on generic method in project B that is specified using class from project C.
Ok, here is the listing:
PROJECT A
ClassA.cs
If you want the code to compile comment first line (
using B;
).Here is a class that includes random extension method in project A.
ExtensionsA.cs
PROJECT B
Extensions.cs - this class has method with generic constraint
T : ClassC
PROJECT C
ClassC.cs - we need this class to use it in extension method in project B
For me it looks like a bug in compiler that is too eager to check if extension method in project B may be used in project A.
Thanks for all your answers! Especially @Rick Sladkey.
在我看来,最可能的答案是
IEnumerable
或IEnumrable
上有一个名为Where
inB 的扩展方法
。此扩展方法使用C
中的类型(作为返回类型?或类型约束?),这需要您引用它。Visual Studio 告诉您
Where
是什么?至于解决方案,似乎
B
在你的控制之下,所以你应该删除扩展方法,它确实不应该在那里。作为替代解决方案,您可以使用长语法:Enumerable.Where(collection, s => s != null)
。The most likely answer seems to me to be that there is an extension method on
IEnumerable
orIEnumrable<T>
calledWhere
inB
. This extension method uses a type fromC
(as return type? or type constraint?) which requires you to reference it.What does Visual Studio tell you
Where
is?As for solution, it seems
B
is under your control, so you should delete the extension method, it really shouldn't be there. As an alternative solution, you can use the long syntax:Enumerable.Where(collection, s => s != null)
.