.Net 继承 - 自动依赖引用行为问题
我遇到了一个我刚刚注意到的奇怪问题。
如果您有一个包含 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一致的行为。第一个是简单引用,第二个是继承。
如果编译了一个程序集并且某个类继承了另一个程序集中的类,则需要该引用来构造它。
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 ofClassB
, it doesn't copy everything fromLibA
(this would produce inconsistent code ifLibA
is updated andClassA
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 fromLibA
(forClassA
) andLibB
(ClassB
) to construct it, thus a direct reference toLibA
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 aboutClassA
as there is no direct usage of that class). If the usage ofClassA
inClassB
was a public field or propety,ClassC
would have a direct reference toClassA
and would need a direct reference to that class definition as well (reference toLibA
fromLibC
).In a different form, this is also the case in the inheritance example.
ClassC
has a direct reference toClassA
(due toClassB
inherting fromClassA
), thus a reference to the declaring assembly (namelyLibA
) is needed to construct the full class definition.是一致的。您必须引用直接使用的任何类型。间接引用被透明地解决。
It is consistant. You must reference any type that you use directly. Indirect references are resolved transparently.
在第一个场景中,您只是使用 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...