我有以下问题。我有一个包含大约 40 个项目的解决方案。有一个项目 A 引用了引用项目 C 的项目 B。项目 A 中没有任何代码使用项目 C 中的类。但是,如果我在任何代码中使用任何 LINQ 扩展方法,例如:
var r = new int[] { 1, 2, 3 }.Where(a => a > 1);
我收到编译器错误:
somefile.cs(70,13): 错误 CS0012: 类型"XXX"在未引用的程序集中定义。必须添加对程序集"项目 C 程序集名称,版本=0.0.0.0,区域性=中性,公钥令牌=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();
更新2:好的,我找到了导致错误的原因。但我不知道为什么。以下代码导致错误:
using System.Linq;
using B;
namespace TestApp
{
public class A
{
public void M()
{
var c = new string[] { "a", "b", "c" }.Where(s => s != null);
}
}
}
但是,如果我使用 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>binDebug</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>binRelease</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, 版本=0.0.0.0, 区域性=中性, 公钥令牌=xxx"的引用。
如果我删除using C;
它可以很好地编译。
提前感谢您的帮助。
下面是一个重现该问题的小示例。 它是由 B 中的扩展方法引起的,该方法在其签名中使用 C 中定义的类型。 即使未使用扩展方法,错误也会由搜索可通过 using 访问的所有扩展方法的过程触发。
控制台应用程序A.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();
}
}
}
类库B.cs:
using ClassLibraryC;
namespace ClassLibraryB
{
public static class Extensions
{
public static ClassC Test(this ClassB b)
{
return new ClassC();
}
}
public class ClassB
{
}
}
类库C.cs:
namespace ClassLibraryC
{
public class ClassC
{
}
}
此测试用例产生此错误:
错误 CS0012:类型"类库C.类C"在未引用的程序集中定义。必须添加对程序集"ClassLibraryC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"的引用。
编辑:
在我看来,这是 C# 编译器中的一个错误,因为对于您未引用的方法来说,它会导致程序编译失败,这是非常令人惊讶的行为。 C# 编译器团队可能有不同的看法。
同时,解决方法是将签名中使用 C 中的类型的扩展方法放在 B 中,并仅在调用程序集同时引用 B 和 C 时才向该命名空间添加 using 。 或者,如果违规扩展方法的数量很少且其值有限,则可以移动或删除它们。 最后,也是最明显的,你可以完成它,只需添加它告诉你应该添加的对 C 的引用。
第二次编辑:
警告:我刚刚审查了这个来清理这个例子,它比我想象的要弱。 仅当 A 中调用的扩展方法的名称与 B 中未调用的扩展方法的名称完全匹配时,它才会失败。 因此,例如,如果您重命名 B 中的 Test
以NotCalled
它不再失败,但在原始问题中,大概它会失败。
最终编辑:
通过合作,我们缩小了重现原始问题中描述的问题的必要条件:B 中的扩展方法,其签名中来自 C 的类型使用泛型类型约束。 上面的测试用例是一个更窄的例子。 具体条件显然与编译器搜索扩展方法的方式的具体实现有关。
总之,引用是运行时功能,扩展方法是编译时功能。 无论错误消息是如何生成的,如果未调用该方法,编译器就是在编译时需要引用的编译器,程序集在运行时不需要引用。 因此,错误不是编译器别无选择,而是发出,这只是编译器的不便情况。
我找到了解决方案。
您可以从以下链接下载整个解决方案(与 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();
}
}
}
如果希望代码编译注释第一行(using B;
)。
下面是一个在项目 A 中包含随机扩展方法的类。
扩展A.cs
namespace A
{
public static class ExtensionsA
{
public static void ExtMethodC(this int[] a)
{
}
}
}
项目 B
扩展.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;
}
}
}
项目 C
ClassC.cs - 我们需要这个类在项目 B 的扩展方法中使用它
namespace C
{
public class ClassC
{
public string Foo;
}
}
对我来说,它看起来像编译器中的一个错误,它太急于检查项目 B 中的扩展方法是否可以在项目 A 中使用。
感谢您的所有回答!尤其是@Rick斯拉德基。
,最有可能的答案是IEnumerable
或IEnumrable<T>
上有一种扩展方法,称为B
中的Where
。此扩展方法使用 C
中的类型(作为返回类型?或类型约束?),这需要您引用它。
Visual Studio告诉你Where
是什么?
至于解决方案,似乎B
在您的控制之下,因此您应该删除扩展方法,它真的不应该存在。作为替代解决方案,您可以使用长语法:Enumerable.Where(collection, s => s != null)
.