如何避免引用仅包含基类的程序集?解决编译报错问题
首先得明确:C#编译器在编译时需要获取所有直接或间接涉及的类型的元数据——哪怕你只实例化派生类MyClass,只要你访问了它继承自MyBase的成员(比如这里的Xyz),编译器就需要MyBase的元数据来验证这个成员的合法性,这就是报错的核心原因。不过我们可以通过几种设计技巧绕过这个要求:
方案1:封装基类成员,对外隐藏基类依赖
如果Xyz是MyBase中定义的属性,你可以在MyClass里重新定义一个同名的公共属性,内部转发到基类实现。这样AssemblyC只需要和MyClass自己的API交互,完全不需要知道MyBase的存在:
// AssemblyB中的MyClass实现 public sealed class MyClass : MyBase { // 封装基类的Xyz属性 public new string Xyz { get => base.Xyz; set => base.Xyz = value; } }
现在在AssemblyC中访问myClass.Xyz时,编译器只会识别MyClass公开的这个属性,不会去查找MyBase的元数据。
方案2:用接口隔离依赖(推荐)
这是更符合面向对象设计原则的做法:定义一个包含所需成员的接口,放在AssemblyB(或者一个独立的公共程序集)中,让MyClass实现该接口,同时继承MyBase。AssemblyC只引用包含接口的程序集,通过接口来操作对象:
// 可以放在AssemblyB或者新建的AssemblyShared中 public interface IMyClass { string Xyz { get; set; } } // AssemblyB中的MyClass public sealed class MyClass : MyBase, IMyClass { public string Xyz { get => base.Xyz; set => base.Xyz = value; } }
然后在AssemblyC中:
IMyClass myClass = new MyClass(); myClass.Xyz = "some text";
这种方式彻底隔离了AssemblyC对MyBase的依赖,同时保留了编译时类型安全,是最推荐的方案。
方案3:用dynamic类型绕过编译检查
如果你的场景对类型安全要求不高,或者只是临时调试,可以用dynamic类型跳过编译时的元数据验证:
dynamic myClass = new MyClass(); myClass.Xyz = "some text";
注意:这种方式会失去编译时类型检查,运行时如果Xyz成员不存在或者类型不匹配,会直接抛出RuntimeBinderException,只适合简单场景。
方案4:调整程序集结构
如果业务允许,你可以直接把MyBase从AssemblyA移到AssemblyB,或者新建一个专门存放公共基类、接口的共享程序集,让AssemblyB和AssemblyC都引用这个共享程序集。这样AssemblyC不需要直接引用AssemblyA,也能获取到基类的元数据。
内容的提问来源于stack exchange,提问作者Amol

