2013-04-03 45 views
5

Tôi có hệ thống lớp .dll giữa ứng dụng của tôi, nơi cấp thấp nhất có một lớp cung cấp chức năng nhất định - một thể hiện của lớp này có thể nhận được thông qua GetClass() chức năng và sau đó tôi có thể truy cập các thuộc tính của nó (về cơ bản, một tập hợp các thông tin của các đối tượng thay đổi).hiển thị loại tham chiếu (lớp) mà không cần tham chiếu bổ sung

Bây giờ tôi nhận thấy rằng khi tôi muốn truy cập thông tin đó từ cấp cao hơn tiếp theo .dll, trình biên dịch phàn nàn rằng tôi không có trình độ thấp hơn .dll được tham chiếu (lớp xác định lớp) - mà thực sự tôi muốn để tránh, để có một cấu trúc lớp đẹp trong kiến ​​trúc của tôi.

Làm cách nào để giải quyết vấn đề này? Tôi có thể hiển thị lại loại được tham chiếu không? Tôi có thực sự phải viết một wrapper của riêng tôi, nếu tôi muốn chính xác cùng một chức năng? Hoặc tôi thậm chí cần phải tham khảo các cấp độ thấp .dll một lần nữa?

(Nếu giúp:

dll1: class myClass, myClass GetMyClass() 
dll2: myClass GetMyClass() 
exe: how to access result from calling GetMyClass (dll2) without referencing dll1? 

)

+0

Bạn sẽ cần phải tải lắp ráp có chứa các lớp học trong thời gian chạy để trả lại lớp. – Romoku

Trả lời

1

Dường như không có cách nào để đạt được điều này, nếu myClass được xác định trong dll1, vì các đối tượng thuộc loại myClass có thể được khởi tạo khi chạy. Để tránh điều này, bạn cần phải thay đổi loại trả lại là GetMyClass() trong dll2 để trả về một số thứ được xác định trong dll2. Nó có thể là một lớp khá giống với myClass và có các thuộc tính giống nhau (thậm chí bạn có thể sử dụng các công cụ như AutoMapper để dễ dàng chuyển đổi giữa các đối tượng), nhưng nó chắc chắn phải ở trong dll2. Một cái gì đó như:

// 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

Trên thực tế, tôi đã đi cho một giải pháp tương tự .. như của bây giờ (sau này refactoring có thể) Tôi phơi bày các chức năng từ myClass như chức năng của dll2 (mỗi lần nhận được một đối tượng myClass). (Tùy thuộc vào bao nhiêu người cuối cùng sẽ được tôi có thể cần phải thay đổi cách tiếp cận để một cái gì đó neater.) –

1

Người gọi phải có một tham chiếu đến lớp trong DLL1 biết những gì loại nó được truy cập. Vì vậy, có bạn cần phải tham khảo dll đầu tiên trong exe. Kể từ khi GetMyClass() trả về một loại trong DLL1 loại cần phải được tiếp xúc trong exe, do đó dll1 phải được tham chiếu.

1

Một giải pháp ở đây là cung cấp DLL thứ 4 chứa giao diện cho lớp học của bạn. Bạn sẽ tham chiếu điều này trong tất cả 3 lớp của bạn và trả về các giao diện này thay vì các lớp của bạn.

này sẽ cung cấp cho bạn một ý tưởng tốt về những gì tôi muốn nói:

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

Sẽ trung thực dù, layering kiến ​​trúc của bạn như thế này thường không phải là một ý tưởng tuyệt vời nếu dự án của bạn là thực sự lớn. Tôi thấy rằng việc lắp ráp nhân tạo tách ra như thế này trước thời hạn có thể khiến bạn đau đớn không cần thiết, chưa kể đến thực tế là bạn kết thúc với 3-4 hội đồng cho một dự án vừa hoặc nhỏ chỉ có thể cần 1.

+0

Nói chung tôi cho rằng bạn là đúng. Trong trường hợp này, dll thấp nhất (dll1) là một dll bên ngoài, vì vậy tôi không thể kết hợp nó, ngoài ra, chúng ta cần một lớp bổ sung (dll2) cho các chức năng nâng cao được chia sẻ cho các ứng dụng. –

3

Bạn cần để tách tất cả các lớp phổ biến mà bạn sử dụng trên tất cả các lớp của bạn thành một dll mới, sau đó tham khảo dll này trên mọi dự án.

Hãy thử sử dụng interfaces để bạn có thể làm việc trên hợp đồng (chức năng) thay vì triển khai cụ thể. Nó sẽ giúp bạn tránh các tham chiếu không cần thiết.

// 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

Giải pháp tuyệt vời! Tôi quên nói rằng tôi không thể thay đổi dll1 vì nó là bên ngoài. Tuy nhiên, tôi giữ thiết kế của bạn trong tâm trí .. Tôi chắc chắn một cái gì đó tương tự sẽ bật lên một lần nữa. –

+0

Xem thêm: [mô hình cầu thang] (http://stackoverflow.com/questions/29259414/stairway-pattern-implementation) – dlf

2

Chúng tôi làm điều tương tự như vậy trong mã cục bộ của chúng tôi.Bạn có thể nạp assembly vào thời gian chạy, quét các kiểu nó chứa sử dụng sự phản chiếu, và một lần nữa sử dụng các chức năng gọi phản chiếu và các kiểu khởi tạo từ dll đó, mà không bao giờ tham chiếu nó trực tiếp trong dự án.

một số chức năng quan trọng, bạn sẽ cần là:

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 

Khi bạn có các loại, phản ánh cơ bản sẽ cung cấp cho bạn khá nhiều mỗi mảnh khác mà bạn cần.

Dưới đây là đoạn mã từ mã địa phương của tôi:

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

Cũng lưu ý: đây là mã khá cũ bây giờ. Nó đã không được xem xét và cũng không được tái cấu trúc trong nhiều năm, do đó, nó cơ bản hiện đại như của .NET 1.1, NHƯNG: Nó minh họa quan điểm. Cách tải loại từ một cụm từ xa không được tham chiếu cục bộ.

Ngoài ra, đây là một phần của động cơ tải 50 trong số này, được cung cấp cấu trúc thư mục cứng nhắc, đó là lý do tại sao nó trông rất chung chung. Lấy những gì bạn cần từ nó.

+1

Điều quan trọng cần nhớ là bạn DONT thực sự có định nghĩa kiểu cục bộ, vì vậy mọi thứ bạn làm với nó phải được thực hiện thông qua sự phản ánh ... Thuộc tính, phương pháp, _everything_. Những gì mã của chúng tôi có là một giao diện cục bộ mà tất cả các "mô-đun" của chúng tôi thực hiện, để chúng tôi có một cái gì đó để xử lý chúng như là cục bộ mà không cần xử lý tất cả các mã phản chiếu. Các mô-đun lần lượt trực tiếp tham khảo giao diện cấp cao để họ có thể thực hiện nó. – Nevyn

+0

Cảm ơn! Giải pháp tốt. Tuy nhiên .. Tôi "tham khảo động" dll1, mà cuối cùng là khá tương tự. (Tôi có thể phải làm điều đó mặc dù vì một lý do khác: các phiên bản không tương thích khác nhau của dll với các chữ ký khác nhau được chọn lọc tùy thuộc vào hoàn cảnh. Oh, dll1 là một thành phần bên ngoài, trong trường hợp bạn tự hỏi về những thứ như vậy ..) –

Các vấn đề liên quan