公开引用的类型(类)而不需要额外的引用

时间:2013-04-03 16:12:33

标签: c# dll reference layer

我的应用程序之间有一个.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?

6 个答案:

答案 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

正确理解这个想法