Làm thế nào mà Microsoft tạo ra các tập hợp có tham chiếu vòng tròn?


107

Trong .NET BCL có các tham chiếu vòng giữa:

  • System.dllSystem.Xml.dll
  • System.dllSystem.Configuration.dll
  • System.Xml.dllSystem.Configuration.dll

Đây là ảnh chụp màn hình từ .NET Reflector cho thấy ý tôi:

nhập mô tả hình ảnh ở đây

Đối với tôi, Microsoft đã tạo ra những tổ hợp này như thế nào là một bí ẩn. Có phải quy trình biên dịch đặc biệt để cho phép điều này không? Tôi tưởng tượng điều gì đó thú vị đang diễn ra ở đây.


2
Câu hỏi rất hay. Tôi chưa bao giờ thực sự dành thời gian để kiểm tra điều này, nhưng tôi tò mò muốn biết câu trả lời. Thật vậy, có vẻ như Dykam đã cung cấp một điều hợp lý.
Noldorin

3
tại sao những dll đó không được hợp nhất thành một, nếu tất cả chúng đều yêu cầu nhau? có lý do thực tế nào cho điều đó không?
Andreas Petersson

1
Câu hỏi thú vị ... Tôi muốn biết câu trả lời của Eric Lippert cho câu hỏi này! Và như Andreas nói, tôi tự hỏi tại sao họ không đặt tất cả mọi thứ trong cùng một assembly ...
Thomas Levesque

Chà nếu một cụm cần được cập nhật, họ sẽ không cần chạm vào những cái khác. Đó là lý do duy nhất tôi thấy. Câu hỏi thú vị mặc dù
Atmocreations

2
Hãy xem bản trình bày này (tệp asmmeta): msakademik.net/academicdays2005/Serge_Lidin.ppt
Mehrdad Afshari

Câu trả lời:


58

Tôi chỉ có thể cho biết Dự án Mono thực hiện điều này như thế nào. Định lý này khá đơn giản, mặc dù nó gây ra một mớ mã.

Đầu tiên họ biên dịch System.Configuration.dll, mà không cần phần tham chiếu đến System.Xml.dll. Sau đó, họ biên dịch System.Xml.dll theo cách bình thường. Bây giờ đến điều kỳ diệu. Họ biên dịch lại System.configuration.dll, với phần cần tham chiếu đến System.Xml.dll. Bây giờ có một biên dịch thành công với tham chiếu vòng tròn.

Nói ngắn gọn:

  • A được biên dịch mà không cần mã cần B và tham chiếu đến B.
  • B được biên dịch.
  • A được biên dịch lại.

1
Nó bị chặn bởi Visual Studio, nhưng có thể được thực hiện trực tiếp bằng trình biên dịch dòng lệnh (csc.exe). Hãy xem câu trả lời của tôi.
Alfred Myers

14
Tôi biết. Hệ thống xây dựng chính của Mono không phải là Visual Studio. Đoán Microsofts cũng không.
Dykam

35

RBarryYoung và Dykam đang làm gì đó. Microsoft sử dụng công cụ nội bộ sử dụng ILDASM để tháo rời các tập hợp, loại bỏ tất cả các nội dung bên trong / riêng tư và thân phương thức và biên dịch lại IL (sử dụng ILASM) thành cái được gọi là 'lắp ráp mất nước' hoặc lắp ráp siêu dữ liệu. Điều này được thực hiện mỗi khi giao diện công cộng của assembly được thay đổi.

Trong quá trình xây dựng, các tập hợp siêu dữ liệu được sử dụng thay vì các tập hợp thực. Theo cách đó chu kỳ bị phá vỡ.


1
Câu trả lời thú vị, bạn có bất kỳ liên kết nào?
Henk Holterman

Tôi đang cố gắng tìm tham chiếu bên ngoài cho công cụ. Tôi không nghĩ rằng nó được xuất bản bên ngoài Microsoft, nhưng khái niệm rất đơn giản: tháo rời-dải bên trong-lắp ráp lại.
Srdjan Jovcic

Đồng ý - câu trả lời thú vị. Một số liên kết để sao lưu điều này sẽ tốt.
Drew Noakes

Vâng, đó thực sự là cách nó được thực hiện (từ kinh nghiệm cá nhân).
Pavel Minaev

1
Chúng không được ký kết mạnh mẽ cho đến sau khi xây dựng (chúng được ký kết chậm trễ), vì vậy các tổ hợp bị mất nước không được ký kết.
Srdjan Jovcic

26

Nó có thể được thực hiện theo cách Dykam đã mô tả nhưng Visual Studio chặn bạn làm điều đó.

Bạn sẽ phải sử dụng trực tiếp trình biên dịch dòng lệnh csc.exe.

  1. csc / target: thư viện ClassA.cs

  2. csc / target: thư viện ClassB.cs /reference:ClassA.dll

  3. csc / target: thư viện ClassA.cs ClassC.cs /reference:ClassB.dll


//ClassA.cs
namespace CircularA {
    public class ClassA {
    }
}


//ClassB.cs
using CircularA;
namespace CircularB {
    public class ClassB : ClassA  {
    }
}


//ClassC.cs
namespace CircularA {
    class ClassC : ClassB {
    }
}

Bạn cũng có thể thực hiện điều này trong Visual studio mặc dù nó cũng khá khắc nghiệt, cách cơ bản là sử dụng # if và xóa tham chiếu bằng trình khám phá giải pháp, đảo ngược điều đó trong bước thứ ba. Một cách khác mà tôi đang nghĩ đến là tệp dự án thứ ba bao gồm các tệp giống nhau nhưng các tham chiếu khác nhau. Điều này sẽ hoạt động vì bạn có thể chỉ định thứ tự xây dựng.
Dykam

Theo như tôi biết, không thể kiểm tra nó ở đây.
Dykam

Tôi thực sự muốn thấy điều đó. Từ những gì tôi đã thử nghiệm ở đây, thời điểm bạn cố gắng Thêm Tham chiếu, IDE sẽ ngăn bạn lại.
Alfred Myers

Tôi biết. Nhưng dự án thứ ba không có tham chiếu đó VÀ ký hiệu #if và được tham chiếu bởi dự án thứ hai, được tham chiếu bởi dự án đầu tiên. Không có chu kỳ. Nhưng cái thứ ba sử dụng mã của cái đầu tiên và xuất ra vị trí lắp ráp đầu tiên. một bộ phận lắp ráp có thể dễ dàng được thay thế bằng bộ phận khác có cùng thông số kỹ thuật. Nhưng tôi nghĩ rằng việc đặt tên mạnh có thể gây ra sự cố trong phương pháp này.
Dykam

Nó hơi giống câu trả lời của Srdjan, mặc dù một phương pháp khác.
Dykam

18

Nó khá dễ thực hiện trong Visual Studio miễn là bạn không sử dụng tham chiếu dự án ... Hãy thử cách này:

  1. Mở studio trực quan
  2. Tạo 2 dự án Thư viện lớp "ClassLibrary1" & "ClassLibrary2".
  3. Xây dựng
  4. Từ ClassLibrary1, thêm một tham chiếu đến ClassLibrary2 bằng cách duyệt đến dll đã tạo ở bước 3.
  5. Từ ClassLibrary2, thêm một tham chiếu đến ClassLibrary1 bằng cách duyệt đến dll đã tạo ở bước 3.
  6. Xây dựng lại (Lưu ý: nếu bạn thực hiện thay đổi trong cả hai dự án, bạn sẽ cần phải xây dựng hai lần để làm cho cả hai tham chiếu đều "mới")

Vì vậy, đây là cách bạn làm điều đó. Nhưng nghiêm túc mà nói ... Bạn không bao giờ làm điều đó trong một dự án thực sự! Nếu bạn làm vậy, ông già Noel sẽ không mang quà cho bạn trong năm nay.


1
Ngoại lệ duy nhất nếu đó là từ ngày 26 đến ngày 31 tháng 12 và quà đã được bảo đảm
Jesse Hufstetler

6

Tôi đoán nó có thể được thực hiện bằng cách bắt đầu với một tập hợp các cụm xoay vòng và sử dụng ILMerge để sau đó kết hợp các tập hợp nhỏ hơn thành các nhóm liên quan một cách hợp lý.


4

Chà, tôi chưa bao giờ làm điều đó trên Windows, nhưng tôi đã làm điều đó trên rất nhiều môi trường biên dịch-liên kết-rtl đóng vai trò là người giám sát thực tế cho nó. Những gì bạn làm trước tiên là tạo các "mục tiêu" sơ khai mà không có các tham chiếu chéo sau đó liên kết, sau đó thêm các tham chiếu vòng tròn, sau đó liên kết lại. Các trình liên kết thường không quan tâm đến các tham chiếu vòng tròn hoặc sau các chuỗi tham chiếu, họ chỉ quan tâm đến việc có thể tự giải quyết từng tham chiếu.

Vì vậy, nếu bạn có hai thư viện, A và B cần tham chiếu lẫn nhau, hãy thử một cái gì đó như sau:

  1. Liên kết A mà không có bất kỳ giới thiệu nào với B.
  2. Liên kết B với đến A.
  3. Liên kết A, thêm các giới thiệu vào B.

Dykam có một điểm tốt, Đó là biên dịch, không liên kết trong .Net, nhưng nguyên tắc vẫn như cũ: Tạo các nguồn được tham chiếu chéo của bạn, với các điểm nhập được xuất của chúng, nhưng với tất cả ngoại trừ một trong số chúng có tham chiếu riêng của chúng với các nguồn khác bị khai thác ngoài. Hãy xây dựng chúng như vậy. Sau đó, xóa các tham chiếu bên ngoài và xây dựng lại chúng. Điều này sẽ hoạt động ngay cả khi không có bất kỳ công cụ đặc biệt nào, trên thực tế, cách tiếp cận này đã hoạt động trên mọi hệ điều hành mà tôi đã từng dùng thử (khoảng 6 trong số chúng). Mặc dù rõ ràng thứ gì đó tự động hóa nó sẽ là một trợ giúp lớn.


định lý là đúng. Tuy nhiên trong thế giới .Net, liên kết được thực hiện động và không phải là một vấn đề. Đó là bước biên dịch mà giải pháp này là cần thiết.
Dykam

Rất tiếc phải sửa lại bạn nhé: P. Nhưng tham chiếu (liên kết) tại thời điểm biên dịch xảy ra trong thế giới .Net, là mọi thứ bắt nguồn từ thông số kỹ thuật ECMA cụ thể đó. Do đó Mono, dotGnu và .Net. Không phải bản thân Windows.
Dykam

1

Một cách tiếp cận khả thi là sử dụng biên dịch có điều kiện (#if) để biên dịch System.dll trước tiên không phụ thuộc vào các tập hợp khác đó, sau đó biên dịch các tập hợp khác và cuối cùng biên dịch lại System.dll để bao gồm các phần phụ thuộc vào Xml và Cấu hình.


1
Đáng tiếc là điều này không cho phép bạn có điều kiện tham khảo một hội đồng (Tôi muốn nó là có thể, nó sẽ thực sự giúp đỡ trong một trong những dự án của tôi ...)
Thomas Levesque

1
Tham chiếu có điều kiện có thể dễ dàng thực hiện bằng cách chỉnh sửa tệp .csproj. Chỉ cần thêm thuộc tính Điều kiện vào phần tử <Tham khảo>.
Daniel

0

Về mặt kỹ thuật, có thể những thứ này hoàn toàn không được biên soạn và lắp ráp bằng tay. Rốt cuộc đây là những thư viện cấp thấp.


Không hẳn vậy. Không có nhiều thứ cấp thấp trong đó, chỉ có cơ bản. Điều gì khiến bạn nghĩ rằng nó sẽ ở mức thấp? Thời gian chạy và nút chai ở mức thấp. Tương đối. Vẫn là C hoặc C ++ đơn giản, nghĩ rằng JIT chứa những thứ cấp thấp.
Dykam
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.