Bagaimana Microsoft membuat majelis yang memiliki referensi melingkar?

107

Di .NET BCL ada referensi melingkar antara:

  • System.dll dan System.Xml.dll
  • System.dll dan System.Configuration.dll
  • System.Xml.dll dan System.Configuration.dll

Berikut tangkapan layar dari .NET Reflector yang menunjukkan apa yang saya maksud:

masukkan deskripsi gambar di sini

Bagaimana Microsoft menciptakan majelis ini adalah misteri bagi saya. Apakah diperlukan proses kompilasi khusus untuk memungkinkan ini? Saya membayangkan sesuatu yang menarik sedang terjadi di sini.

Drew Noakes
sumber
2
Pertanyaan yang sangat bagus. Saya tidak pernah benar-benar meluangkan waktu untuk memeriksanya, tetapi saya ingin tahu jawabannya. Memang, sepertinya Dykam telah memberikan yang masuk akal.
Noldorin
3
mengapa dll itu tidak digabung menjadi satu, jika semuanya saling membutuhkan? apakah ada alasan praktis untuk itu?
Andreas Petersson
1
Pertanyaan menarik ... Saya ingin tahu jawaban Eric Lippert untuk yang satu ini! Dan seperti yang dikatakan Andreas, saya bertanya-tanya mengapa mereka tidak meletakkan semuanya di majelis yang sama ...
Thomas Levesque
Jika satu rakitan perlu diperbarui, mereka tidak perlu menyentuh yang lain. Itulah satu-satunya alasan saya melihat. Pertanyaan yang menarik meskipun
Atmocreations
2
Lihatlah presentasi ini (file asmmeta): msakademik.net/academicdays2005/Serge_Lidin.ppt
Mehrdad Afshari

Jawaban:

58

Saya hanya bisa tahu bagaimana Proyek Mono melakukan ini. Teorema ini cukup sederhana, meskipun memberikan kekacauan kode.

Mereka pertama-tama mengkompilasi System.Configuration.dll, tanpa bagian yang membutuhkan referensi ke System.Xml.dll. Setelah ini, mereka mengkompilasi System.Xml.dll dengan cara biasa. Sekarang datang keajaiban. Mereka mengkompilasi ulang System.configuration.dll, dengan bagian yang membutuhkan referensi ke System.Xml.dll. Sekarang ada kompilasi yang berhasil dengan referensi melingkar.

Pendeknya:

  • A dikompilasi tanpa kode yang membutuhkan B dan referensi ke B.
  • B dikompilasi.
  • A dikompilasi ulang.
Dykam
sumber
1
Ini diblokir oleh Visual Studio, tetapi dapat dilakukan menggunakan kompiler baris perintah (csc.exe) secara langsung. Lihat jawaban saya.
Alfred Myers
14
Aku tahu. Sistem build utama Mono bukanlah Visual Studio. Kira Microsoft juga tidak.
Dykam
35

RBarryYoung dan Dykam sedang merencanakan sesuatu. Microsoft menggunakan alat internal yang menggunakan ILDASM untuk membongkar rakitan, menghapus semua barang internal / pribadi dan badan metode dan mengkompilasi ulang IL lagi (menggunakan ILASM) menjadi apa yang disebut 'rakitan dehidrasi' atau rakitan metadata. Ini dilakukan setiap kali antarmuka publik perakitan diubah.

Selama pembuatan, rakitan metadata digunakan sebagai ganti yang asli. Dengan cara itu siklus terputus.

Srdjan Jovcic
sumber
1
Jawaban menarik, apakah Anda punya tautan?
Henk Holterman
Saya mencoba mencari referensi eksternal ke alat tersebut. Saya tidak berpikir itu diterbitkan di luar Microsoft, tetapi konsepnya sederhana: membongkar-strip internal-memasang kembali.
Srdjan Jovcic
Setuju - jawaban yang menarik. Beberapa tautan untuk mendukung ini akan bagus.
Drew Noakes
Ya, memang begitu caranya (dari pengalaman pribadi).
Pavel Minaev
1
Mereka tidak ditandatangani dengan kuat sampai setelah dibangun (mereka ditunda ditandatangani), jadi majelis dehidrasi tidak ditandatangani.
Srdjan Jovcic
26

Ini dapat dilakukan dengan cara yang dijelaskan Dykam tetapi Visual Studio menghalangi Anda melakukannya.

Anda harus menggunakan kompilator baris perintah csc.exe secara langsung.

  1. csc / target: perpustakaan ClassA.cs

  2. csc / target: perpustakaan ClassB.cs /reference:ClassA.dll

  3. csc / target: perpustakaan 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 {
    }
}
Alfred Myers
sumber
Anda juga dapat melakukan ini di Visual studio meskipun itu cukup sulit juga, cara dasarnya adalah menggunakan # if's dan menghapus referensi menggunakan explorer solusi, membalikkannya di langkah ketiga. Cara lain yang saya pikirkan adalah file proyek ketiga termasuk file yang sama tetapi referensi berbeda. Ini akan berfungsi karena Anda dapat menentukan urutan build.
Dykam
Sejauh yang saya tahu, tidak bisa mengujinya di sini.
Dykam
Saya sangat ingin melihat itu. Dari percobaan saya di sini, saat Anda mencoba Menambahkan Referensi, IDE akan menghentikan Anda.
Alfred Myers
Aku tahu. Tapi proyek ketiga tidak memiliki referensi itu DAN simbol #if, dan direferensikan oleh yang kedua, yang direferensikan oleh yang pertama. Tanpa siklus. Tetapi yang ketiga menggunakan kode yang pertama dan keluaran ke lokasi perakitan pertama. sebuah rakitan dapat dengan mudah diganti dengan yang lain dengan spesifikasi yang sama. Tapi saya pikir pemberian nama yang kuat dapat menyebabkan masalah dalam metode ini.
Dykam
Ini sedikit seperti jawaban Srdjan, meskipun metodenya berbeda.
Dykam
18

Ini cukup mudah dilakukan di Visual Studio selama Anda tidak menggunakan referensi proyek ... Coba ini:

  1. Buka studio visual
  2. Buat 2 proyek Perpustakaan Kelas "ClassLibrary1" & "ClassLibrary2".
  3. Membangun
  4. Dari ClassLibrary1 tambahkan referensi ke ClassLibrary2 dengan menjelajahi dll yang dibuat pada langkah 3.
  5. Dari ClassLibrary2, tambahkan referensi ke ClassLibrary1 dengan menjelajahi dll yang dibuat pada langkah 3.
  6. Bangun lagi (Catatan: jika Anda membuat perubahan di kedua proyek, Anda perlu membuat dua kali untuk membuat kedua referensi menjadi "segar")

Jadi begini caramu melakukannya. Tapi serius ... Bukankah Anda PERNAH melakukannya dalam proyek nyata! Jika ya, Santa tidak akan membawakanmu hadiah tahun ini.

JohannesH
sumber
1
Satu-satunya pengecualian adalah jika itu terjadi antara 26-31 Desember dan hadiah sudah diamankan
Jesse Hufstetler
6

Saya kira itu bisa dilakukan dengan memulai dengan kumpulan asiklik dan menggunakan ILMerge untuk kemudian menggabungkan majelis yang lebih kecil ke dalam kelompok yang terkait secara logis.

Steve Gilham
sumber
4

Yah, saya belum pernah melakukannya di Windows, tetapi saya telah melakukannya di banyak lingkungan compile-link-rtl yang berfungsi sebagai nenek moyang praktis untuk itu. Yang Anda lakukan adalah membuat rintisan "target" terlebih dahulu tanpa referensi silang, lalu tautan, lalu tambahkan referensi melingkar, lalu tautkan kembali. Linker umumnya tidak peduli tentang referensi melingkar atau mengikuti rantai referensi, mereka hanya peduli tentang kemampuan menyelesaikan setiap referensi sendiri.

Jadi jika Anda memiliki dua pustaka, A dan B yang perlu mereferensikan satu sama lain, coba sesuatu seperti ini:

  1. Tautkan A tanpa referensi ke B.
  2. Tautkan B dengan referensi ke A.
  3. Link A, menambahkan referensi ke B.

Dykam membuat poin yang bagus, Ini dikompilasi, bukan menautkan di .Net, tetapi prinsipnya tetap sama: Buat sumber referensi silang Anda, dengan titik masuk yang diekspor, tetapi dengan semua kecuali satu dari mereka memiliki referensi sendiri ke yang lain yang dipotong di luar. Bangun mereka seperti itu. Kemudian, hapus potongan referensi eksternal dan buat kembali. Ini harus bekerja bahkan tanpa alat khusus, pada kenyataannya, pendekatan ini telah bekerja pada setiap sistem operasi yang pernah saya coba (sekitar 6 di antaranya). Meskipun jelas sesuatu yang mengotomatiskan itu akan sangat membantu.

RBarryYoung
sumber
teorema benar. Namun di dunia .Net, penautan dilakukan secara dinamis dan tidak menjadi masalah. Ini adalah langkah kompilasi dimana solusi ini dibutuhkan.
Dykam
Maaf memperbaiki Anda lagi: P. Tetapi referensi (menghubungkan) pada waktu kompilasi terjadi di dunia .Net, yang merupakan segala sesuatu yang diturunkan dari spesifikasi ECMA tertentu. Jadi Mono, dotGnu dan .Net. Bukan Windows itu sendiri.
Dykam
1

Salah satu pendekatan yang mungkin adalah menggunakan kompilasi bersyarat (#if) untuk terlebih dahulu mengkompilasi System.dll yang tidak bergantung pada rakitan lain tersebut, kemudian mengkompilasi rakitan lain, dan terakhir mengkompilasi ulang System.dll untuk memasukkan bagian-bagian yang bergantung pada Xml dan Konfigurasi.

Daniel
sumber
1
Sayangnya ini tidak memungkinkan Anda untuk merujuk secara bersyarat sebuah majelis (saya berharap itu mungkin, itu akan sangat membantu dalam salah satu proyek saya ...)
Thomas Levesque
1
Referensi bersyarat dapat dengan mudah dilakukan dengan mengedit file .csproj. Cukup tambahkan atribut Kondisi ke elemen <Referensi>.
Daniel
0

Secara teknis, mungkin ini tidak dikompilasi sama sekali, dan dirakit dengan tangan. Ini adalah perpustakaan tingkat rendah.

tylermac.dll
sumber
Tidak juga. Tidak banyak barang tingkat rendah di dalamnya, hanya dasar. Apa yang membuatmu berpikir itu level rendah? Runtime dan corlib adalah level rendah. Relatif. Masih polos C atau C ++, mengira JIT berisi barang tingkat rendah.
Dykam