2

好吧,我很清楚我的问题的标题太复杂了。我只是试图使其尽可能具体。所以,我会尝试更好地解释这个问题。

问题上下文

假设我们在一个解决方案中有三个 .NET 项目。主项目是一个简单的控制台应用程序ApplicationAssembly。该项目引用了另一个托管程序集库DirectlyReferencedLibrary。同时 DirectlyReferencedLibrary 指的是IndirectlyUsedLibrary

因此,项目用法如下所示: ApplicationAssembly --> DirectlyReferencedLibrary --> IndirectlyUsedLibrary

请注意,ApplicationAssembly 不直接使用任何声明为 IndirectlyUsedLibrary 的类型。我们还假设在这些程序集中声明的所有类型都驻留在同一个命名空间中。

该解决方案可以编译并正常工作。

奇怪的问题

当我同时满足以下条件时会出现问题:

  1. ApplicationAssembly项目使用了LINQ 表达式。例如,如果在任何可枚举类型的对象上调用 Select()。
  2. DirectlyReferencedLibrary声明了一个具有类型限制的通用扩展方法的类。类型限制表示泛型类型必须是IndirectlyUsedLibrary类的后代。

这是此类的示例。

using System;

namespace Test
{
    public static class UnUsedType
    {
        // It's a generic extension method with a type restriction.
        public static void Magic<T>(this T @this)
            // It's a type restriction that uses a type from the IndirectlyUsedLibrary.
            where T : ProblemType
        {
            Console.WriteLine("I do nothing actually.");
        }
    }
}

当我尝试编译这个项目时,我收到以下错误:

错误类型“Test.ProblemType”在未引用的程序集中定义。您必须添加对程序集“IndirectlyUsedLibrary,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的引用。C:\Projects\Test\ApplicationAssembly\Program.cs 22 13 ApplicationAssembly

问题

谁能帮我理解为什么会这样?

附言

我为调查做了一个微小的解决方案。如果您愿意帮助我,您将可以在此处获取存档的解决方案

聚苯乙烯

对不起我的英语不好。

UPD1

另一个奇怪的事情是 LINQ 方法的不同调用可能会也可能不会产生编译时错误:

// Ok. Let's do some work using LINQ we love so much!
var strings = new[] { "aaa", "bbb", "ccc" };
Func<string, object> converter = item => (object) item;

// The following line makes problems.
var asObjects1 = strings.Select(converter);

// Everything is OK if we use the following line:
var asObjects2 = Enumerable.Select(strings, converter);
4

3 回答 3

14

谁能帮我理解为什么会这样?

C# 编译器有合理的期望,即引用程序集的传递闭包在编译时可用。它没有任何高级逻辑来解释它肯定需要、可能需要、可能不需要或绝对不需要知道的东西,以解决程序将要抛出的类型分析中的所有问题. 如果您直接或间接引用程序集,编译器会假定其中可能有它需要的类型信息。

此外,如果您在编译时没有一组引用的程序集,那么用户在运行时会拥有它们的期望是什么?期望编译时环境至少具有运行时所需的程序集集似乎是合理的。

我不想这样做。

我们都必须做我们在生活中不想做的事情。

于 2011-12-21T23:30:03.380 回答
2

我想你知道这一点,但是因为类型ProblemType是在“IndirectlyUsedLibrary”中定义的,但它是Magic扩展方法的必需定义,它必须被引用才能在编译时可用。

至于“为什么”......好吧,编译器需要知道它正在编译的细节,不是吗?对我来说,编译器需要与运行时相同的最小编译时引用集,这很有意义......

于 2011-12-21T23:36:42.277 回答
1

如果您对库使用不同的命名空间,则不会出现错误。在不同的库中使用相同的命名空间真的很奇怪。

一旦您第一次使用任何扩展名,编译器就会开始扫描您的 Test 命名空间以查找扩展名。因此需要参考。

于 2011-12-21T23:11:59.933 回答