Sự khác biệt giữa Hội đồngVersion, Hội đồng hội thảo và Hội nghị Thông tin là gì?


860

Có ba thuộc tính phiên bản lắp ráp. Sự khác biệt là gì? Có ổn không nếu tôi sử dụng AssemblyVersionvà bỏ qua phần còn lại?


MSDN nói:

  • Hội đồng :

    Chỉ định phiên bản lắp ráp được quy kết.

  • HộiFileVersion :

    Hướng dẫn trình biên dịch sử dụng số phiên bản cụ thể cho tài nguyên phiên bản tệp Win32. Phiên bản tệp Win32 không bắt buộc phải giống với số phiên bản của tổ hợp.

  • Hội đồng thông tin :

    Xác định thông tin phiên bản bổ sung cho một bảng kê khai lắp ráp.


Đây là phần tiếp theo Các thực tiễn tốt nhất để sử dụng Thuộc tính hội là gì?

Câu trả lời:


907

Hội đồng

Trường hợp các hội đồng khác tham chiếu lắp ráp của bạn sẽ nhìn. Nếu số này thay đổi, các hội đồng khác phải cập nhật tài liệu tham khảo của họ cho hội đồng của bạn! Chỉ cập nhật phiên bản này, nếu nó phá vỡ tính tương thích ngược. Điều AssemblyVersionbắt buộc.

Tôi sử dụng định dạng: Major.minor . Điều này sẽ dẫn đến:

[assembly: AssemblyVersion("1.0")]

Nếu bạn đang theo dõi SemVer một cách nghiêm ngặt thì điều này có nghĩa là bạn chỉ cập nhật khi những thay đổi lớn , vì vậy 1.0, 2.0, 3.0, v.v.

HộiFileVersion

Được sử dụng để triển khai. Bạn có thể tăng số lượng này cho mỗi lần triển khai. Nó được sử dụng bởi các chương trình thiết lập. Sử dụng nó để đánh dấu các hội đồng có cùng AssemblyVersion, nhưng được tạo từ các bản dựng khác nhau.

Trong Windows, nó có thể được xem trong thuộc tính tệp.

Hội đồng hội thảo là tùy chọn. Nếu không được đưa ra, hội đồng được sử dụng.

Tôi sử dụng định dạng: Major.minor.patch.build , nơi tôi theo dõi SemVer cho ba phần đầu tiên và sử dụng bản dựng của máy chủ xây dựng cho phần cuối cùng (0 cho bản dựng cục bộ). Điều này sẽ dẫn đến:

[assembly: AssemblyFileVersion("1.3.2.254")]

Hãy lưu ý rằng System.Version đặt tên cho các phần này là major.minor.build.revision!

Hội đồng thông tin

Phiên bản sản phẩm của lắp ráp. Đây là phiên bản bạn sẽ sử dụng khi nói chuyện với khách hàng hoặc để hiển thị trên trang web của bạn. Phiên bản này có thể là một chuỗi, như ' Ứng viên phát hành 1.0 '.

Đây AssemblyInformationalVersionlà tùy chọn. Nếu không được đưa ra, hội đồng hội thảo được sử dụng.

Tôi sử dụng định dạng: Major.minor [.patch] [sửa đổi dưới dạng chuỗi] . Điều này sẽ dẫn đến:

[assembly: AssemblyInformationalVersion("1.0 RC1")]

4
Đối với hộiFileVersion, "Nếu có thể, hãy để nó được tạo bởi MSBuild" - Tại sao? Bạn vừa tiếp tục giải thích một lý do chính đáng để tự điều khiển nó :)
mo.

3
Cảnh báo về định dạng AssociationInformalVersion vẫn tồn tại trong VS2010 ngày hôm nay (21 tháng 5 năm 2013) và liên kết của bạn đã chết.
Revierpost

22
Thật không may, Lớp Phiên bản định nghĩa major.minor[.build[.revision]]và không phải major.minor.revision.buildnhư vậy trong câu trả lời đã cho, các số bản dựng và sửa đổi sẽ bị hoán đổi nếu bạn đang sử dụng các thuộc tính của lớp hoặc System.Reflection.Assembly.GetExecutingAssembly().GetName().Versionđể phát hiện các số bản dựng và bản sửa đổi.
thinkOfaNumber

9
@thinkOfaNumber Quyền của bạn về Lớp Phiên bản, nhưng đó là cách lập phiên bản của Microsoft. Cá nhân tôi nghĩ thật lạ khi không có bản dựng ở cuối và đó là lý do tại sao tôi chỉ đưa định dạng của mình làm ví dụ, dựa trên Phiên bản ngữ nghĩa . Bạn có thể sử dụng theo cách của Microsoft hoặc theo cách riêng của bạn.
Rémy van Duijkeren

6
Cần lưu ý rằng AssemblyInformationalVersion, nếu bỏ qua, AssemblyFileVersionđược sử dụng. Sau đó, AssemblyVersion nếu cả hai được bỏ qua.
Drazen Bjelovuk

588

Phiên bản của các hội đồng trong .NET có thể là một viễn cảnh khó hiểu do hiện tại có ít nhất ba cách để chỉ định một phiên bản cho hội đồng của bạn.

Dưới đây là ba thuộc tính lắp ráp liên quan đến phiên bản chính:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

Theo quy ước, bốn phần của phiên bản được gọi là Phiên bản chính , Phiên bản nhỏ , Bản dựngSửa đổi .

Mục AssemblyFileVersionđích nhằm xác định duy nhất một bản dựng của lắp ráp riêng lẻ

Thông thường, bạn sẽ tự cài đặt MajorFileVersion theo cách thủ công để phản ánh phiên bản của hội đồng, sau đó tăng Bản dựng và / hoặc Sửa đổi mỗi khi hệ thống bản dựng của bạn biên dịch cụm. Hội đồng hội thảo sẽ cho phép bạn xác định duy nhất một bản dựng của hội đồng, để bạn có thể sử dụng nó làm điểm khởi đầu để gỡ lỗi bất kỳ vấn đề nào.

Trong dự án hiện tại của tôi, chúng tôi có máy chủ xây dựng mã hóa số lượng thay đổi từ kho lưu trữ kiểm soát nguồn của chúng tôi thành các phần Xây dựng và Sửa đổi của Hội đồngFileVersion. Điều này cho phép chúng tôi ánh xạ trực tiếp từ một cụm vào mã nguồn của nó, cho bất kỳ lắp ráp nào được tạo bởi máy chủ xây dựng (mà không phải sử dụng nhãn hoặc các nhánh trong kiểm soát nguồn hoặc giữ thủ công bất kỳ bản ghi nào của các phiên bản đã phát hành).

Số phiên bản này được lưu trữ trong tài nguyên phiên bản Win32 và có thể được nhìn thấy khi xem các trang thuộc tính Windows Explorer để lắp ráp.

CLR không quan tâm và cũng không kiểm tra hội đồngFileVersion.

Mục AssemblyInformationalVersionđích này đại diện cho phiên bản của toàn bộ sản phẩm của bạn

Hội đồng Thông tin được thiết kế để cho phép phiên bản mạch lạc của toàn bộ sản phẩm, có thể bao gồm nhiều hội đồng được phiên bản độc lập, có thể có các chính sách phiên bản khác nhau và có khả năng được phát triển bởi các nhóm khác nhau.

Ví dụ, phiên bản 2.0 của sản phẩm có thể chứa một số cụm; một trong những hội đồng này được đánh dấu là phiên bản 1.0 vì đây là hội đồng mới không xuất xưởng trong phiên bản 1.0 của cùng một sản phẩm. Thông thường, bạn đặt các phần chính và phụ của số phiên bản này để thể hiện phiên bản công khai của sản phẩm. Sau đó, bạn tăng các phần xây dựng và sửa đổi mỗi khi bạn đóng gói một sản phẩm hoàn chỉnh với tất cả các bộ lắp ráp của nó. - Jeffrey Richter, [CLR qua C # (Ấn bản thứ hai)] p. 57

CLR không quan tâm và cũng không kiểm tra hội nghịInformalVersion.

Đây AssemblyVersionlà phiên bản duy nhất mà CLR quan tâm (nhưng nó quan tâm đến toàn bộ AssemblyVersion)

Bộ lắp ráp được CLR sử dụng để liên kết với các cụm được đặt tên mạnh. Nó được lưu trữ trong bảng siêu dữ liệu tệp kê khai của Hội đồng được xây dựng và trong bảng Hội đồng của bất kỳ hội đồng nào tham chiếu đến nó.

Điều này rất quan trọng, bởi vì điều đó có nghĩa là khi bạn tham chiếu một hội đồng có tên mạnh mẽ, bạn bị ràng buộc chặt chẽ với một Hội đồng cụ thể của hội đồng đó. Toàn bộ Hội đồng phải là một kết hợp chính xác để liên kết thành công. Ví dụ: nếu bạn tham chiếu phiên bản 1.0.0.0 của một hội đồng có tên mạnh vào thời gian xây dựng, nhưng chỉ có phiên bản 1.0.0.1 của hội đồng đó có sẵn trong thời gian chạy, ràng buộc sẽ thất bại! (Sau đó, bạn sẽ phải xử lý vấn đề này bằng cách sử dụng Chuyển hướng kết dính .)

Nhầm lẫn về việc liệu toàn bộ AssemblyVersionphải phù hợp. (Vâng, đúng vậy.)

Có một chút nhầm lẫn xung quanh việc liệu toàn bộ Hội đồng có phải là một kết hợp chính xác để một tập hợp được tải hay không. Một số người có niềm tin sai lầm rằng chỉ có các phần Chính và Phần phụ của Hội đồng phải khớp nhau để ràng buộc để thành công. Đây là một giả định hợp lý, tuy nhiên cuối cùng nó không chính xác (kể từ .NET 3.5) và việc xác minh điều này cho phiên bản CLR của bạn là chuyện nhỏ. Chỉ cần thực thi mã mẫu này .

Trên máy của tôi, tải lắp ráp thứ hai không thành công và hai dòng cuối cùng của nhật ký nhiệt hạch làm cho nó hoàn toàn rõ ràng tại sao:

.NET Framework Version: 2.0.50727.3521
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
Successfully loaded assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
Assembly binding for  failed:
System.IO.FileLoadException: Could not load file or assembly 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, 
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's manifest definition 
does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f'

=== Pre-bind state information ===
LOG: User = Phoenix\Dani
LOG: DisplayName = Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
 (Fully-specified)
LOG: Appbase = [...]
LOG: Initial PrivatePath = NULL
Calling assembly : AssemblyBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Post-policy reference: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
LOG: Attempting download of new URL [...].
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

Tôi nghĩ rằng nguồn gốc của sự nhầm lẫn này có lẽ là do Microsoft ban đầu dự định sẽ khoan dung hơn một chút về sự phù hợp chặt chẽ này của Hội nghị toàn diện, bằng cách chỉ khớp trên các phần của phiên bản Chính và phụ:

Khi tải một bản lắp ráp, CLR sẽ tự động tìm phiên bản dịch vụ được cài đặt mới nhất phù hợp với phiên bản chính / phụ của bản lắp ráp được yêu cầu. - Jeffrey Richter, [CLR qua C # (Ấn bản thứ hai)] p. 56

Đây là hành vi trong bản Beta 1 của 1.0 CLR, tuy nhiên tính năng này đã bị xóa trước khi phát hành 1.0 và không được quản lý để hiển thị lại trong .NET 2.0:

Lưu ý: Tôi vừa mô tả cách bạn nên nghĩ về số phiên bản. Thật không may, CLR không xử lý số phiên bản theo cách này. [Trong .NET 2.0], CLR coi số phiên bản là giá trị mờ và nếu một tổ hợp phụ thuộc vào phiên bản 1.2.3.4 của một tổ hợp khác, CLR chỉ cố gắng tải phiên bản 1.2.3.4 (trừ khi có chuyển hướng ràng buộc ). Tuy nhiên Microsoft có kế hoạch thay đổi trình tải của CLR trong phiên bản tương lai để tải bản dựng / sửa đổi mới nhất cho phiên bản chính / phụ của một bản lắp ráp. Ví dụ, trên phiên bản tương lai của CLR, nếu trình tải đang cố gắng tìm phiên bản 1.2.3.4 của phiên bản và phiên bản 1.2.5.0 tồn tại, trình tải sẽ tự động chọn phiên bản phục vụ mới nhất. Đây sẽ là một thay đổi rất đáng hoan nghênh đối với trình tải của CLR - Tôi không thể chờ đợi. - Jeffrey Richter, [CLR qua C # (Ấn bản thứ hai)] p. 164 (mỏ nhấn mạnh)

Vì sự thay đổi này vẫn chưa được thực hiện, tôi nghĩ rằng sẽ an toàn khi cho rằng Microsoft đã theo dõi ngược lại ý định này và có lẽ đã quá muộn để thay đổi điều này ngay bây giờ. Tôi đã cố gắng tìm kiếm trên web để tìm hiểu điều gì đã xảy ra với các kế hoạch này, nhưng tôi không thể tìm thấy bất kỳ câu trả lời nào. Tôi vẫn muốn đi đến tận cùng của nó.

Vì vậy, tôi đã gửi email cho Jeff Richter và hỏi anh ấy trực tiếp - tôi đoán xem có ai biết chuyện gì đã xảy ra không, đó sẽ là anh ấy.

Anh ấy đã trả lời trong vòng 12 giờ, vào một buổi sáng thứ bảy không kém, và làm rõ rằng trình tải .NET 1.0 Beta 1 đã thực hiện cơ chế 'cuộn tự động' này để chọn bản dựng và sửa đổi mới nhất của một hội đồng, nhưng hành vi này là hoàn nguyên trước khi .NET 1.0 xuất xưởng. Sau đó, nó đã được dự định để phục hồi điều này nhưng nó đã không được thực hiện trước khi CLR 2.0 xuất xưởng. Sau đó đến Silverlight, được ưu tiên cho nhóm CLR, vì vậy chức năng này đã bị trì hoãn hơn nữa. Trong khi đó, hầu hết những người xung quanh trong thời kỳ CLR 1.0 Beta 1 đã chuyển đi, vì vậy không có khả năng điều này sẽ thấy ánh sáng ban ngày, bất chấp mọi công việc khó khăn đã được đưa vào.

Hành vi hiện tại, dường như, là ở đây.

Điều đáng chú ý từ cuộc thảo luận của tôi với Jeff rằng Hội đồngFileVersion chỉ được thêm vào sau khi loại bỏ cơ chế 'chuyển tiếp tự động' - bởi vì sau 1.0 Beta 1, mọi thay đổi đối với Hội đồng là một thay đổi đột phá đối với khách hàng của bạn, sau đó không nơi nào để lưu trữ an toàn số xây dựng của bạn. HộiFileVersion là nơi trú ẩn an toàn, vì CLR không bao giờ tự động kiểm tra. Có lẽ nó rõ ràng hơn theo cách đó, có hai số phiên bản riêng biệt, với ý nghĩa riêng biệt, thay vì cố gắng phân tách giữa phần Chính / Nhỏ (phá vỡ) và phần Xây dựng / Sửa đổi (không phá vỡ) của Hội đồng.

Điểm mấu chốt: Hãy suy nghĩ cẩn thận khi bạn thay đổi AssemblyVersion

Đạo đức là nếu bạn vận chuyển các hội đồng mà các nhà phát triển khác sẽ tham khảo, bạn cần phải cực kỳ cẩn thận khi bạn thực hiện (và không) thay đổi Hội nghị của các hội đồng đó. Bất kỳ thay đổi nào đối với Hội đồng sẽ có nghĩa là các nhà phát triển ứng dụng sẽ phải biên dịch lại phiên bản mới (để cập nhật các mục nhập của Hội đồng này) hoặc sử dụng các chuyển hướng liên kết lắp ráp để ghi đè lên ràng buộc.

  • Không thay đổi Lắp ráp cho bản phát hành dịch vụ nhằm tương thích ngược.
  • Đừng thay đổi AssemblyVersion cho một thông cáo mà bạn biết có thay đổi vi phạm.

Chỉ cần nhìn lại các thuộc tính phiên bản trên mscorlib:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

Lưu ý rằng đó là phiên bản hội nghị có chứa tất cả các thông tin phục vụ thú vị (đó là phần Sửa đổi của phiên bản này cho bạn biết Gói dịch vụ nào bạn đang sử dụng), trong khi đó, Hội nghị được khắc phục ở phiên bản 2.0.0.0 cũ nhàm chán. Mọi thay đổi đối với Hội đồng sẽ buộc mọi ứng dụng .NET tham chiếu mscorlib.dll phải biên dịch lại so với phiên bản mới!


9
Câu trả lời chính xác. Tôi nghĩ rằng điểm quan trọng nhất mà bạn đã thực hiện - và những gì MS nên được khuyến nghị rõ ràng - là thực hiện các thay đổi đối với Hội đồng khi và chỉ khi phiên bản mới phá vỡ tính tương thích ngược.
mwolfe02

1
Một trong những câu hỏi tôi liên tục tự hỏi mình là khi nào tôi nên thay đổi từng số phiên bản này, các gạch đầu dòng của bạn trên AssociationVersion đã thêm rõ ràng cho điều này và toàn bộ câu trả lời là một bài đọc thú vị.
RyanfaeScotland

Tôi đang thấy rất nhiều câu trả lời giải thích các khái niệm đằng sau ba điều này. Nhưng làm thế nào để chúng liên quan đến số phiên bản có thể chỉnh sửa trong các thuộc tính dự án? Khi bạn nhấp vào Thông tin hội ... bạn có tùy chọn thay đổi hai phiên bản. Và ở đó, việc thay đổi Phiên bản hội đồng sẽ thay đổi thư mục nơi tìm thấy user.config và việc thay đổi Phiên bản tệp sẽ thay đổi số phiên bản được hiển thị khi bạn nhấp chuột phải vào tệp exe và chuyển đến thuộc tính của nó. Vậy làm thế nào để hai số phiên bản đó tương ứng với AssociationVersion, AssociationFileVersion và AssociationInformalVersion?
Kyle Delaney

Liên kết đến bài đăng blog bạn viết ban đầu cung cấp 404. Có vị trí mới cho điều đó không?
Rob K

@RobK: À, xin lỗi. Trang web đó không hoạt động, nhưng toàn bộ nội dung của bài đăng trên blog được sao chép trong câu trả lời để bạn không bỏ lỡ điều gì. Tôi sẽ xóa liên kết bị hỏng ngay bây giờ.
Daniel Fortunov

43

AssemblyVersionkhá nhiều vẫn là nội bộ của .NET, trong khi đó AssemblyFileVersionlà những gì Windows thấy. Nếu bạn đi đến các thuộc tính của một hội đồng ngồi trong một thư mục và chuyển sang tab phiên bản, thì đó AssemblyFileVersionlà những gì bạn sẽ thấy trên cùng. Nếu bạn sắp xếp các tệp theo phiên bản, đây là những gì được Explorer sử dụng.

Các AssemblyInformationalVersionbản đồ cho "Phiên bản sản phẩm" và hoàn toàn có nghĩa là "con người sử dụng".

AssemblyVersionchắc chắn là quan trọng nhất, nhưng tôi cũng sẽ không bỏ qua AssemblyFileVersion. Nếu bạn không cung cấp AssemblyInformationalVersion, trình biên dịch sẽ thêm nó cho bạn bằng cách tước phần "sửa đổi" của số phiên bản của bạn và để lại Major.minor.build.


23

AssemblyInformationalVersionAssemblyFileVersionđược hiển thị khi bạn xem thông tin "Phiên bản" trên một tệp thông qua Windows Explorer bằng cách xem các thuộc tính tệp. Các thuộc tính này thực sự được biên dịch vào một VERSION_INFOtài nguyên được tạo bởi trình biên dịch.

AssemblyInformationalVersionlà giá trị "Phiên bản sản phẩm". AssemblyFileVersionlà giá trị "Phiên bản tệp".

AssemblyVersionlà đặc trưng cho các hội đồng .NET và được trình tải lắp ráp .NET sử dụng để biết phiên bản nào của một hội đồng sẽ tải / liên kết khi chạy.

Trong số này, thứ duy nhất được .NET yêu cầu hoàn toàn là AssemblyVersionthuộc tính. Thật không may, nó cũng có thể gây ra nhiều vấn đề nhất khi nó thay đổi một cách bừa bãi, đặc biệt nếu bạn mạnh mẽ đặt tên cho hội đồng của mình.


9

Để giữ cho câu hỏi này hiện tại, cần nhấn mạnh rằng AssemblyInformationalVersionNuGet đã sử dụng và phản ánh phiên bản gói bao gồm bất kỳ hậu tố trước khi phát hành.

Ví dụ: Lắp ráp 1.0.3. * Được đóng gói với dotnet-cli lõi asp.net

dotnet pack --version-suffix ci-7 src/MyProject

Tạo một gói với phiên bản 1.0.3-ci-7 mà bạn có thể kiểm tra bằng phản xạ bằng cách sử dụng:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);

7

Đáng chú ý một số điều khác:

1) Như được hiển thị trong hộp thoại Thuộc tính Windows Explorer cho tệp lắp ráp được tạo, có hai vị trí được gọi là "Phiên bản tệp". Cái được nhìn thấy trong tiêu đề của hộp thoại hiển thị AssociationVersion, không phải là AssociationFileVersion.

Trong phần Thông tin phiên bản khác, có một yếu tố khác gọi là "Phiên bản tệp". Đây là nơi bạn có thể thấy những gì đã được nhập với tư cách là AssociationFileVersion.

2) HộiFileVersion chỉ là văn bản thuần túy. Nó không phải tuân theo các hạn chế lược đồ đánh số mà hội đồng thực hiện (<build> <65K, vd). Nó có thể là 3.2. <Phát hành thẻ văn bản>. <Datetime>, nếu bạn muốn. Hệ thống xây dựng của bạn sẽ phải điền vào các mã thông báo.

Hơn nữa, nó không phải là đối tượng thay thế ký tự đại diện mà hộiVersion. Nếu bạn chỉ có một giá trị "3.0.1. *" Trong Hội nghịInfo.cs, đó chính xác là những gì sẽ hiển thị trong thông tin Phiên bản khác-> Phần tử Phiên bản tệp.

3) Tuy nhiên, tôi không biết tác động đến trình cài đặt sử dụng thứ gì đó ngoài số phiên bản tệp số.


2

Khi thay đổi lắp ráp của một hội đồng, Nếu nó có tên mạnh, các hội đồng tham chiếu cần phải được biên dịch lại, nếu không thì hội đồng không tải! Nếu nó không có tên mạnh, nếu không được thêm vào tệp dự án một cách rõ ràng, nó sẽ không được sao chép vào thư mục đầu ra khi xây dựng để bạn có thể bỏ lỡ các cụm tùy chỉnh, đặc biệt là sau khi làm sạch thư mục đầu ra.


Điều này rất thú vị! Bạn có thể giải thích một chút về phần "sẽ không được sao chép vào thư mục đầu ra" không? Có lẽ một liên kết đến nơi hành vi này được xác định. Tôi không bao giờ hiểu tại sao một số phụ thuộc gián tiếp đôi khi được sao chép, nhưng không phải lúc nào cũng vậy. Điều này phải liên quan 100% với nó.
julealgon
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.