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;它编译就好了.
在此先感谢您的帮助.
这是一个重现问题的小例子.它是由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类型使用泛型类型约束.上述测试用例是一个较窄的例子.具体条件显然与编译器搜索扩展方法的具体实现有关.
总之,引用是运行时功能,扩展方法是编译时功能.无论如何生成错误消息,如果未调用该方法,编译器是在编译时需要引用的编译器,程序集在运行时不需要引用.因此,错误不是编译器除了发射之外别无选择的错误,这对编译器来说只是一个不方便的情况.
我找到了解决方案。
您可以从此链接下载整个解决方案(相对于 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。