6

我的应用程序之间有一个分层的 .dll 系统,其中最低级别有一个提供某些功能的类 - 可以通过 GetClass() 函数接收此类的实例,然后我可以访问它的属性(基本上是一个集合变化对象的信息)。

现在我注意到,当我想从下一个更高级别的 .dll 访问该信息时,编译器抱怨我没有引用较低级别的 .dll(定义类的那个) - 实际上我想避免这种情况在我的架构中有一个很好的分层结构。

如何解决这个问题?我可以重新公开引用的类型吗?如果我想要完全相同的功能,我真的必须编写自己的包装器吗?还是我什至需要再次引用低级 .dll?

DLL 1:

class myClass;
myClass GetMyClass();

动态链接库 2:

myClass GetMyClass();

EXE文件:

如何在不引用 DLL 1 的情况下访问调用 GetMyClass (DLL 2) 的结果?

4

6 回答 6

4

您需要将您在所有层中使用的所有公共类分离到一个新的 dll 中,然后在每个项目中引用这个 dll。

尝试使用接口,以便您可以处理合同(功能)而不是具体实现。它将帮助您避免不必要的引用。

// 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);
    }
}
于 2013-04-03T16:23:23.567 回答
2

myClass如果在 中定义,似乎没有办法实现这一点dll1,因为类型的对象myClass可能在运行时被实例化。为避免这种情况,您需要更改 in 的返回类型GetMyClass()dll2返回 in 中定义的内容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
}
于 2013-04-03T16:19:07.197 回答
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 个,给定一个严格的文件夹结构,这就是它看起来如此通用的原因。从中获取你需要的东西。

于 2013-04-03T18:44:05.390 回答
1

调用者必须具有对 DLL1 中的类的引用才能知道它正在访问什么类型。所以是的,您需要引用exe中的第一个dll。由于 GetMyClass() 在 DLL1 中返回一个类型,该类型需要在 exe 中公开,因此必须引用 dll1。

于 2013-04-03T16:18:36.100 回答
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 个装配。

于 2013-04-03T16:19:15.260 回答
1

我和尼克一起使用任何 Ioc 框架,如 spring.net 或 microsoft unity。要正确理解这个想法,请通过http://martinfowler.com/articles/injection.html

于 2013-04-03T16:26:19.440 回答