我的应用程序之间有一个.dll分层系统,其中最低级别有一个提供某些功能的类 - 这个类的实例可以通过GetClass()函数接收,然后我可以访问它的属性(基本上,一组变化对象的信息。)
现在我注意到,当我想从下一个更高级别.dll访问该信息时,编译器抱怨我没有引用较低级别.dll(定义类的那个) - 实际上我想要避免,在我的架构中有一个很好的分层结构。
如何解决这个问题?我可以重新公开引用的类型吗?如果我想要完全相同的功能,我真的必须写一个我自己的包装器吗?或者我甚至需要再次引用低级别.dll?
(如果有帮助:
dll1: class myClass, myClass GetMyClass()
dll2: myClass GetMyClass()
exe: how to access result from calling GetMyClass (dll2) without referencing dll1?
)
答案 0 :(得分:4)
您需要将所有图层中使用的所有常用类分隔为新的dll,然后在每个项目中引用此dll。
尝试使用interfaces,以便您可以处理合同(功能)而不是具体实现。它将帮助您避免不必要的引用。
// common dll
public interface IMyClass
{
string MyData { get; set; }
IMyClass GetMyClass();
}
// dll1
public class myClass : IMyClass
{
public string MyData { get; set; }
public IMyClass GetMyClass() { return new myClass() { MyData = "abc" }; }
}
// dll2
public class myClass2
{
public IMyClass GetMyClass()
{
var c1 = new myClass();
var c2 = c1.GetMyClass();
return c2;
}
}
// exe (references common and dll2)
public class Program
{
public static void Main(string[] args)
{
var c1 = new myClass2();
IMyClass c2 = c1.GetMyClass();
Console.Writeline(c2.MyData);
}
}
答案 1 :(得分:2)
如果在myClass
中定义dll1
,似乎无法实现此目的,因为myClass
类型的对象可能在运行时被实例化。为避免这种情况,您需要更改GetMyClass()
中dll2
的返回类型,以返回dll2
中定义的内容。它可以是一个与myClass
非常相似且具有相同属性的类(您甚至可以使用AutoMapper之类的工具轻松地在对象之间进行转换),但它绝对应该在dll2
中。类似的东西:
// dll1
class myClass
{
...
}
myClass GetMyClass()
{
...
}
// dll2
class myClass2
{
public myClass2(myClass c)
{
// instantiate myClass2 with values from myClass
}
}
myClass2 GetMyClass()
{
// somehow get myClass and convert it to myClass2 here
}
答案 2 :(得分:2)
我们在本地代码中执行与此类似的操作。您可以在运行时加载程序集,使用反射扫描它包含的类型,并再次使用反射调用函数并从该dll实例化类型,而无需直接在项目中引用它。
您需要的一些关键功能是:
Assembly.LoadFrom(path); //get the assembly as a local object
Activator.CreateInstance(type); //create an instance of a type
Assembly.GetType(string);//fetch a type by name from the assembly
一旦你有了这种类型,基本的反射将为你提供你需要的所有其他部分。
以下是我当地代码的摘录:
asm = Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, filePath));
Type[] types = asm.GetTypes();
for (var x = 0; x < types.Length; x++)
{
var interfaces = types[x].GetInterfaces();
for (var y = 0; y < interfaces.Length; y++)
{
if (interfaces[y].Name.Equals("MyTypeName"))
{
isValidmod = true;
var p = (IMyType)Activator.CreateInstance(types[x]);
//Other stuff
}
}
另请注意:现在这是非常古老的代码。它多年来一直没有被审查或重构,所以它在.NET 1.1中基本上是现代的,但是:它说明了这一点。如何从未在本地引用的远程程序集加载类型。
此外,这是一个引擎的一部分,加载了其中的50个,给定一个严格的文件夹结构,这就是为什么它如此通用的外观。从中获取所需的一切。
答案 3 :(得分:1)
调用者必须在DLL1中引用该类才能知道它正在访问的类型。所以是的,你需要在exe中引用第一个dll。由于GetMyClass()在DLL1中返回一个类型,因此需要在exe中公开该类型,因此必须引用dll1。
答案 4 :(得分:1)
这里的一个解决方案是提供包含类的接口的第4个DLL。您可以在所有3个图层中引用它,并返回这些接口而不是类。
这应该可以让你清楚我的意思:
// DLL1
class ClassInDLL1 : IClassInDLL1
{
}
// DLL2
class ClassInDLL2
{
public IClassInDLL1 GetClassInDLL1()
{
return new ClassInDLL1();
}
}
// DLL3
class ClassInDLL3
{
public void DoSomething()
{
var dll2 = new ClassInDLL2();
var dll1 = dll2.GetClassInDLL1(); // dll1 variable is of type IClassInDLL1
// do stuff with dll1
}
}
// interface DLL
interface IClassInDLL1
{
}
我会说实话,除非您的项目非常庞大,否则将这样的架构分层,这通常不是一个很棒的想法。我发现人工制作这样的装配拆分可能会给你造成不必要的痛苦,更不用说你最终会为一个可能只需要1的中型或小型项目组装3-4个组件。
答案 5 :(得分:1)
我使用任何Ioc框架(如spring.net或microsoft unity)与Nick一起使用。通过http://martinfowler.com/articles/injection.html
正确理解这个想法