2013-04-03 91 views
5

我有申請中,在最低水平具有類,它提供特定的功能之間的.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

您需要在運行時加載包含該類的程序集才能返回該類。 – Romoku

回答

1

如果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 
} 
+0

其實,我去了一個類似的解決方案..截至目前(稍後重構可能)我公開函數從myClass作爲dll2的功能(每次獲得一個myClass對象)。 (取決於最終會有多少人,我可能需要將方法改爲更簡潔的方法。) –

1

調用者必須在DLL1類的引用知道它是什麼訪問類型。所以是的,你需要引用exe中的第一個dll。由於GetMyClass()在DLL1中返回一個類型,因此該類型需要在exe中公開,因此必須引用dll1。

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 
{ 
} 

我會說實話,雖然,分層體系結構像這通常不是一個真棒想法,除非你的項目是非常大的。我發現,人爲地進行組裝的分裂這樣的時間提前,可以使你不必要的痛苦,更何況你最終3-4組件的中小型項目,可能只需要1

+0

通常我想你是對的。在這種情況下,最低的dll(dll1)是一個外部的dll,所以我不能將它組合起來,另外,我們還需要一個額外的圖層(dll2)來實現爲應用程序共享的高級功能。 –

3

您需要的事實將所有圖層中使用的所有常用類分離爲新的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); 
    } 
} 
+0

不錯的解決方案!我忘了說我不能改變dll1,因爲它是外部的。不過,我始終記住你的設計。我相信類似的東西會再次出現。 –

+0

另請參見:[樓梯模式](http://stackoverflow.com/questions/29259414/stairway-pattern-implementation) – dlf

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

但要記住的關鍵是,你不必在本地實際上有類型定義,所以你做的每件事與它必須通過反射完成...屬性,方法,_everything_。我們的代碼具有的是我們所有「模塊」實現的本地接口,因此我們可以在本地處理它們,而無需處理所有反射代碼。模塊反過來直接引用高層接口,以便他們能夠實現它。 – Nevyn

+0

謝謝!好的解決方案仍然..我「動態引用」dll1,它最終是相當相似。 (我可能必須這樣做,因爲另一個原因:不同的不兼容版本的dll具有不同的簽名,根據具體情況有選擇性地加載。噢,dll1是一個外部組件,以防萬一你想知道這樣的事情。) –