【问题标题】:.Net Inheritance - Automatic dependency referencing behavior issue.Net Inheritance - 自动依赖引用行为问题
【发布时间】:2011-05-25 14:49:54
【问题描述】:

我遇到了一个我刚刚注意到的奇怪问题。

如果您有 3 个项目的解决方案

** 注意讨论后编辑**

项目 LibA - 有一个 ClassA

namespace LibA
{
    public class ClassA
    {
        public override string ToString()
        {
            return "The logic in class A!";
        }
    }
}

项目 LibB - 有一个 ClassB

using LibA;

namespace LibB
{
    public class ClassB
    {
        public ClassA a;

        public ClassB()
        {
            a = new ClassA();
        }

        public object Foo()
        {
            return a;
        }
    }
}

项目 LibC - 有一个 ClassC

using LibB;

namespace LibC
{
    public class ClassC
    {
        public ClassB b;

        public ClassC()
        {
            b = new ClassB();
        }

        public object Foo()
        {
            return b.Foo();
        }
    }
}

终于有试驾了

using System;
using LibC;

namespace Shell
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassC c = new ClassC();
            Console.WriteLine(c.Foo());
        }
    }
}

现在,如果您编译它,一切都会完美运行。如果您检查 LibC 的二进制文件夹的内容,您会看到它自动滚动通过依赖链以确定它需要拉入 LibA 和 LibB

但是,如果您将 ClassB 更改为从 A 类继承 比如

using LibA;

namespace LibB
{
    public class ClassB : ClassA
    {
        ClassA a;
    }
}

尝试编译,会报错

错误 2 类型“LibA.ClassA”在未引用的程序集中定义。您必须添加对程序集“LibA,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的引用。

** 原始问题**

有谁知道为什么(无论是 msbuild 还是 Visual Studio)当 ClassA 是 ClassB 的成员时引用 LibA 足够聪明,但当 ClassA 是 ClassB 的基类时引用 LibA 不够聪明?

我知道这很挑剔,但我真的很感激一些一致的行为

** 用这些观察到的测试修正了问题 **

我听说有些人将其定义为“直接”或“间接”引用。然而,直接显然不仅仅是可见性范围,它似乎是一种类型的继承和实际使用。

在没有继承的情况下,测试驱动程序足够聪明,可以解析并自动引用 LibA、LibB 和 LibC。

在 ClassB 中有一个可见的 public 成员 ClassA,但仅此一项不会产生编译/链接错误。

调试器肯定会从测试驱动程序中解析 ClassA,因此它清楚地加载了正确的程序集。

所以考虑到所有这些。我现在得到了整个“直接”和“间接”的东西。

为什么链接器/编译器/IDE 至少不尝试在“直接”场景中自动引用被引用库的依赖项,仍然没有点击我的东西?知道存在依赖关系并在“间接”场景中引用它们显然足够聪明。

【问题讨论】:

  • 绝对有趣。作为前 VB.NET 的人,这是我无法理解的。 VB.NET 编译器足够智能,可以链接项目依赖项;为什么没有 C# 编译器?

标签: c# inheritance reference dependencies


【解决方案1】:

在第一个场景中,您只是使用 ClassA。因此,它在编译时不需要资源,只在运行时需要。

在第二种情况下,您从 ClassA 继承,因此编译器需要它的定义和信息来构建最终程序集。

在第一个场景中,VisualStudio 将引用的 DLL 复制到输出目录中,因为它知道您在那里需要它。

在第二种情况下,VisualStudio 不会添加对项目的引用,我认为这是您的主要疑问。我想这是为了避免干扰您的项目而出现问题。但是,我只是猜测......

【讨论】:

    【解决方案2】:

    这是一致的行为。第一个是简单的引用,第二个是继承。

    如果一个程序集被编译并且一个类从另一个程序集中的一个类继承,则需要该引用来构造它。

    LibB 仅包含在ClassB 的类定义中添加的信息,它不会从LibA 复制所有内容(如果LibA 是更新和ClassA 更改,同时LibB 仍将包含旧信息)。

    所以要在LibC 中使用继承的类定义,它需要来自LibA(对于ClassA)和LibBClassB)的信息来构造它,因此直接引用@987654332需要@。

    在示例中,对不同程序集的类的所有引用都是私有的,因此只需要下一级(ClassC 不需要知道 ClassA,因为没有直接使用该类)。如果在ClassB 中使用ClassA 是公共字段或属性,则ClassC 将直接引用ClassA,并且还需要直接引用该类定义(从@ 引用LibA 987654340@)。

    在不同的形式中,继承示例也是如此。 ClassC 直接引用了ClassA(由于ClassB 继承自ClassA),因此需要引用声明程序集(即LibA)来构造完整的类定义。

    【讨论】:

    • 我明白为什么继承需要这些信息。我想知道如果 LibC 是成员,为什么它会自动复制 LibA 和 LibB,如果它是继承的,为什么它不会自动复制 LibA 和 LibB
    • 因为在仅引用的情况下LibB 需要LibA 的信息(请注意,在所有情况下,引用的类都是私有字段,因此不会暴露给外部,所以使用类不要不需要知道)。然而,在继承的情况下,ClassB 仍然是ClassC 的成员,但ClassB 继承ClassA,因此ClassC 也需要了解ClassA(以构造完整的类定义)。
    • 在此注释中,我将 ClassA 公开为 ClassB 中的公共变量,它仍然自动引用 LibC 中的 LibA。但是,就您而言,当我确实尝试使用该公共变量做某事时,它确实要求从 LibC 中显式引用 LibA。
    • 你没有暴露ClassA,你把它暴露为一个对象。因此,您在 ClassC 中没有对 ClassA 的引用。请在您的方法中将object 换成ClassA
    • 我现在得到了“直接/间接”的东西。不管改foo返回ClassA,我想知道VS自动引用是直接还是间接有什么问题?
    【解决方案3】:

    我知道这很挑剔,但我会 真的很感谢一些一致的 行为

    它是一致的。您必须引用您直接使用的任何类型。间接引用被透明地解析。

    【讨论】:

    • 你在考虑什么间接引用?正如您在我对 B 类的修订中看到的那样,它直接引用了 A 类
    • 但是ClassC不知道ClassA,所以不需要直接引用。 (ClassAClassB 的私有字段,因此ClassC 不可见)。
    猜你喜欢
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-25
    • 1970-01-01
    • 1970-01-01
    • 2016-09-11
    • 1970-01-01
    相关资源
    最近更新 更多