.Net 继承 - 自动依赖引用行为问题

发布于 2024-10-07 14:41:10 字数 2129 浏览 0 评论 0原文

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

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

** 注意经过讨论后编辑 **

项目 LibA - 具有 A 类

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

项目 LibB - 具有 B 类

using LibA;

namespace LibB
{
    public class ClassB
    {
        public ClassA a;

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

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

项目 LibC - 具有 C 类

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;
    }
}

尝试编译,您将收到错误

Error 2 The type 'LibA.ClassA' is Defined in an assembly that is not referenced。您必须添加对程序集“LibA,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的引用。

**原始问题**

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

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

**通过这些观察到的测试修正问题**

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

无需继承,测试驱动程序就足够智能,可以解析并自动引用 LibA、LibB 和 LibC。

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

调试器确实从测试驱动程序中解析了 ClassA,因此它显然加载了正确的程序集。

考虑到这一切。我现在得到了整个“直接”和“间接”的东西。

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

I've come across a strange issue that I've just now noticed.

If you have a solution with 3 projects

** NOTE Edited after discussion **

Project LibA - Has a ClassA

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

Project LibB - Has a ClassB

using LibA;

namespace LibB
{
    public class ClassB
    {
        public ClassA a;

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

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

Project LibC - Has a ClassC

using LibB;

namespace LibC
{
    public class ClassC
    {
        public ClassB b;

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

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

Finally a test driver

using System;
using LibC;

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

Now if you compile this, everything will work perfectly. If you examine the contents of LibC's binary folder, you'll see that it automatically rolled through the chain of dependencies to determine that it needed to pull in LibA and LibB

However, if you alter ClassB to inherit from class A
such as

using LibA;

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

attempt to compile, you'll get the error

Error 2 The type 'LibA.ClassA' is defined in an assembly that is not referenced. You must add a reference to assembly 'LibA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

** Original Question **

Does anyone know why (whether it is msbuild or visual studio) it is smart enough to reference LibA when ClassA a member of ClassB, but it isn't smart enough to reference LibA when ClassA is the base class of ClassB?

I know it's nitpicky, but I would really appreciate some consistent behavior

** Amended Question with these observed tests **

I'm hearing what some define as "direct" or "indirect" references. However, direct is clearly not just the visibility scoping, it seems to be inheritance and actual usage of a type.

Without inheritance, the test driver is smart enough to resolve and automatically reference LibA, LibB and LibC.

There is a public member ClassA visible in ClassB and yet that alone doesn't produce the compilation/linking error.

The debugger definitely resolves ClassA from the test driver, so it clearly loaded the correct assembly.

So with all that in mind. I get the whole "direct" and "indirect" stuff now.

The thing that is still not clicking to me why the linker/compiler/IDE doesn't at least try to automatically reference the dependencies of a referenced library in an "direct" scenario? It's clearly smart enough to know the dependencies are there and reference them in an "indirect" scenario.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

悸初 2024-10-14 14:41:10

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

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

LibB 仅包含 ClassB 的类定义中添加的信息,它不会复制 LibA 中的所有内容> (如果更新 LibA 并更改 ClassA,这会产生不一致的代码,而 LibB 仍将包含旧信息)。

因此,要在 LibC 中使用继承的类定义,它需要来自 LibA(对于 ClassA)和 LibB 的信息> (ClassB) 来构造它,因此需要直接引用LibA

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

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

This is consistent behaviour. The first one is a simple reference, the second one is inheritance.

If an assembly is compiled and a class inherits from a class in another assembly, that reference is required to construct it.

LibB only contains the information that is added in the class definition of ClassB, it doesn't copy everything from LibA (this would produce inconsistent code if LibA is updated and ClassA is changed while doing that, LibB would still contain the old information).

So to use an inherited class definition in LibC, it needs both the information from LibA (for ClassA) and LibB (ClassB) to construct it, thus a direct reference to LibA is needed.

In the example, all references to classes of different assemblies are private, thus only the next level is neeed (ClassC doesn't need to know about ClassA as there is no direct usage of that class). If the usage of ClassA in ClassB was a public field or propety, ClassC would have a direct reference to ClassA and would need a direct reference to that class definition as well (reference to LibA from LibC).

In a different form, this is also the case in the inheritance example. ClassC has a direct reference to ClassA (due to ClassB inherting from ClassA), thus a reference to the declaring assembly (namely LibA) is needed to construct the full class definition.

拥抱影子 2024-10-14 14:41:10

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

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

I know it's nitpicky, but I would
really appreciate some consistent
behavior

It is consistant. You must reference any type that you use directly. Indirect references are resolved transparently.

意犹 2024-10-14 14:41:10

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

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

在第一种情况下,VisualStudio将引用的 DLL 复制到输出目录,因为它知道您在那里需要它。

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

In the first scenario, you are just using the ClassA. So, it does not need the resource at compile time, just at run time.

In the second scenario, you are inheriting from ClassA, so, its definition and information is needed by the compiler in order to build the final assembly.

In the first scenario, VisualStudio copies the referenced DLL into the output directory, because it knows you'll need it there.

In the second scenario, VisualStudio does not add the reference to the project, and that's I assume, your main doubt. I guess it's meant that way in order to avoid problems by being intrusive in your project. But, I'm just guessing...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文