无需其他引用即可公开引用的类型(类)

问题描述 投票:6回答:6

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

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

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

DLL 1:

class myClass;
myClass GetMyClass();

DLL 2:

myClass GetMyClass();

EXE:

如何通过调用GetMyClass(DLL 2)而不引用DLL 1来访问结果?

c# dll reference layer
6个回答
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
}

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);
    }
}

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左右,这就是其外观如此通用的原因。从中获取所需的东西。


1
投票

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


1
投票

我与Nick一起使用spring.net或Microsoft unity之类的任何Ioc框架。为了正确理解这个想法,请通过http://martinfowler.com/articles/injection.html


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个装配体了。

© www.soinside.com 2019 - 2024. All rights reserved.