我遇到了一个我刚才注意到的奇怪问题。
如果您有3个项目的解决方案
**注意讨论后编辑**
Project LibA - 有一个ClassA
namespace LibA
{
public class ClassA
{
public override string ToString()
{
return "The logic in class A!";
}
}
}
Project LibB - 有一个ClassB
using LibA;
namespace LibB
{
public class ClassB
{
public ClassA a;
public ClassB()
{
a = new ClassA();
}
public object Foo()
{
return a;
}
}
}
Project 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? / p>
我知道这很挑剔,但我真的很感激一些一贯的行为
**这些观察到的测试的修正问题**
我听到一些人定义为“直接”或“间接”的引用。但是,直接显然不仅仅是可见性范围,它似乎是一种类型的继承和实际使用。
没有继承,测试驱动程序足够聪明,可以解析并自动引用LibA,LibB和LibC。
在ClassB中可以看到 public 成员ClassA,但仅此一项不会产生编译/链接错误。
调试器肯定会从测试驱动程序中解析ClassA,因此它显然加载了正确的程序集。
所有这一切都在考虑之中。我现在得到了整个“直接”和“间接”的东西。
仍然没有点击我的话为什么链接器/编译器/ IDE至少不会尝试在“直接”场景中自动引用引用库的依赖关系?显然足够聪明,可以知道依赖关系,并在“间接”场景中引用它们。
答案 0 :(得分:4)
这是一致的行为。第一个是简单的引用,第二个是继承。
如果编译了一个程序集,并且一个类继承自另一个程序集中的一个类,则需要该引用来构造它。
LibB
仅包含ClassB
的类定义中添加的信息,它不会复制LibA
中的所有内容(这会产生不一致)代码如果更新了LibA
并且在执行此操作时更改了ClassA
,LibB
仍会包含旧信息。
因此,要在LibC
中使用继承的类定义,它需要来自LibA
(对于ClassA
)和LibB
(ClassB
)的信息构建它,因此需要直接引用LibA
。
在该示例中,对不同程序集的类的所有引用都是私有的,因此只需要下一级(ClassC
不需要知道ClassA
,因为没有直接使用它类)。如果ClassA
中ClassB
的使用属于公共字段或属性,则ClassC
将直接引用ClassA
,并且还需要直接引用该类定义(引自LibA
的{{1}})。
在另一种形式中,继承示例中也是如此。 LibC
直接引用ClassC
(由ClassA
引起ClassB
),因此需要引用声明程序集(即ClassA
)构造完整的类定义。
答案 1 :(得分:0)
我知道这很挑剔,但我愿意 真的很欣赏一些 行为
它是一致的。您必须引用您直接使用的任何类型。间接引用是透明解决的。
答案 2 :(得分:0)
在第一个场景中,您只是使用ClassA 。因此,它在编译时不需要资源,只是在运行时。
在第二种情况中,您继承自ClassA ,因此,编译器需要其定义和信息才能构建最终的程序集。
在第一个场景中,VisualStudio 将引用的DLL复制到输出目录,因为它知道你需要它。
在第二种情况下,VisualStudio不会添加对项目的引用,而我认为这是您的主要疑问。我想这意味着通过在项目中侵入来避免问题。但是,我只是猜测......