2012-02-08 40 views
5

Câu hỏi này là nhiều hơn về C# hơn là về log4net (tôi nghĩ).Constructor tĩnh được gọi hai lần trong cùng một miền appdomain?

Tôi đã tạo một appender tùy chỉnh và để cho nó đọc một trường tĩnh được thiết lập trước đó bởi chương trình.

Ngạc nhiên thay, trường tĩnh đã được khởi tạo lại và giá trị cài đặt dit không được đặt cho ứng dụng.

Tôi đã kích hoạt bản sửa lỗi và thấy rằng hàm tạo tĩnh được gọi hai lần (!). Điều này không nên có thể trong cùng một miền appdomain phải không? Chỉ debugview đưa điều này để ánh sáng kể từ khi VS đã không nhấn một lần thứ hai trên breakpoint.

Lưu ý rằng đây không phải là câu hỏi về việc tránh sử dụng biến tĩnh với log4net. Tôi quan tâm đến loại log4net ma thuật nào sử dụng để thực hiện điều này?

Chỉnh sửa # 1

Xin chào John, Big fan hâm mộ.

Tôi bị cô lập thêm theo yêu cầu. Đầu tiên tôi bắt đầu để trống và làm việc hướng tới tình huống đích để lộ ra lỗi. Vì tôi gần như phù hợp với nhân vật mục tiêu của nhân vật và vẫn không repro tôi đã đi theo cách khác tròn.

Bắt đầu từ tình huống lỗi Tôi đã loại bỏ mọi thứ mà tôi cho là không cần thiết cho đến khi nó bắt đầu ... hoạt động như mong đợi.

Có vẻ như có một số điều hoing lạ trên khi thời gian chạy cố gắng để giải quyết việc lắp ráp log4net (như quan sát thấy trong chế độ gỡ lỗi)

Đây là những gì tôi thấy với debugview:

[7756] chung: CẢNH BÁO - Không thể phân tích cú pháp phiên bản 'log4net' của mô-đun. Ngoại lệ: System.NullReferenceException: Tham chiếu đối tượng không được đặt thành một thể hiện của một đối tượng. [7756] tại DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor (Chuỗi modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version) [7756] Chung: WARN - Không thể phân tích cú pháp phiên bản 'FollowUp.Common' của mô-đun. Ngoại lệ: System.NullReferenceException: Tham chiếu đối tượng không được đặt thành một thể hiện của một đối tượng. [7756] tại DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor (String modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version)

Và VS cho thấy không có giá trị cho các con đường trong màn hình debug-mô-đun. Bây giờ tôi đã xoay xở để đi đến tình huống đó như thế nào? Thật lạ khi nó quản lý để tải một hội đồng nhưng không thể nói được nữa từ đâu :)

Đây là tình huống bị cô lập đến mức nếu tôi sửa đổi nó hơn nữa nó bắt đầu hoạt động như mong đợi.

https://www.sugarsync.com/pf/D6486369_1701716_00940

tôi vẫn còn quan tâm đến những chi tiết kỹ thuật nhưng sau khi loại bỏ các tham chiếu đến log4net và thêm nó một lần nữa nó tất cả bắt đầu hoạt động trở lại. Tôi rất vui vì nó hoạt động nhưng nó làm tôi khó hiểu rằng tôi không có giải thích kỹ lưỡng

Ngoài ra, hàm tạo tĩnh * được gọi là hai lần bây giờ có ý nghĩa vì kiểu được khởi tạo lại khi log4net được trên đó.

Tôi nghĩ rằng nó không phải là đáng giá để dành nhiều thời gian hơn vào nguyên nhân này tôi nghĩ rằng giải pháp là trong một trạng thái kỳ lạ và để hiểu tất cả điều này có giá trị biên. Tuy nhiên, nếu bạn có thể nghĩ ra điều gì đó để giải thích điều này tôi sẽ vui mừng khi đến đây.

Chỉnh sửa # 2

Hóa ra là một số hội đồng đã được thực sự nạp hai lần trong đó có một với constructor tĩnh. Tôi sẽ điều tra sau này như thế nào là có thể nhưng tôi có một workaround bằng cách vô hiệu hóa và kích hoạt Costura. Costura là một tác vụ msbuild kết hợp tất cả các assembly thành một. Tôi không nói rằng Costura là nguyên nhân gốc rễ. Có thể dễ dàng là tệp csproj/sln ở trạng thái lạ.

Suy nghĩ về cách chẩn đoán vấn đề này nhanh hơn trong tương lai, tôi đã kích hoạt ProcessExplorer sysinternals. Bây giờ tôi mong đợi để xem các hội đồng được nạp chỉ một lần nhưng tôi thấy thấy rằng họ đã được nạp hai lần. Có vẻ đây là một lỗi trong thats runtime cố định duy nhất trong .NET 4

http://forum.sysinternals.com/why-some-net-assemblies-are-duplicated-in-memory_topic15279.html https://connect.microsoft.com/VisualStudio/feedback/details/467560/clr-maps-assemblies-into-the-virtual -address-space-twice

Chỉnh sửa # 3 Costura đã thực hiện lắp ráp hai lần. Vấn đề đã được chủ sở hữu dự án cố định vào cùng ngày :) http://code.google.com/p/costura/issues/detail?id=17&thanks=17&ts=1328826304

Chúng tôi cần thẻ Costura nhưng tôi không có 1500 điểm danh tiếng cần thiết. Vui lòng tạo nó nếu bạn có quyền. Cảm ơn.

Kind Regards, Tom

+1

"Chỉ bản sửa lỗi đã đưa điều này ra ánh sáng vì VS không đạt lần thứ hai trên điểm ngắt." <--- Tôi bỏ phiếu cho một lỗi trong debugview như là một nguyên nhân có khả năng hơn của vấn đề này. Tôi thực sự tò mò những gì thực sự đã xảy ra ở đó :) – dasblinkenlight

+0

Xin chào dasblinkenlight. Debugview là một người quan sát thuần túy, tôi không thấy nó tạo ra bất kỳ tác dụng phụ nào. Nếu gỡ lỗi chọn Trace.Writeline hai lần có nghĩa là mã đã được thực hiện hai lần và debugview không có gì để làm với nó. – buckley

+1

Điều này đã không xảy ra, đá lạnh cứng đảm bảo. Quên việc xóa trình theo dõi mặc định là một lỗi phổ biến. –

Trả lời

4

Có vẻ như bạn đã quản lý để tải hai trường hợp riêng biệt log4net vào cùng một AppDomain.

Một tài liệu tham khảo dự án:

<Reference Include="log4net"> 
    <HintPath>..\packages\log4net.1.2.11\lib\net35-full\log4net.dll</HintPath> 
</Reference> 

Các khác:

<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL"> 
    <SpecificVersion>False</SpecificVersion> 
    <HintPath>..\ExternalReferences\log4net.dll</HintPath> 
</Reference> 

Một trong số đó được đặt tên mạnh mẽ, khác không phải là, điều này dẫn đến .net đem lại cho họ bản sắc khác nhau. Và đường dẫn gợi ý cũng khác. Ngoài ra, có vẻ như là 1.2.10, số khác 1.2.11.

thử gọi AppDomain.GetAssemblies() và kiểm tra xem log4net có xảy ra hai lần không.

+0

Xin chào CodeInChaos. Cảm ơn bạn đã chỉ ra điều này và đặc biệt là giải thích tại sao điều này là có thể. Bạn cũng biết lý do tại sao điều này kích hoạt rằng các nhà xây dựng tĩnh (và do đó khởi tạo trường tĩnh) được gọi là hai lần? Họ đang ở trong cùng một miền appdomain, vì vậy tôi mong đợi họ chia sẻ tĩnh. – buckley

+3

Nếu hai trường hợp của hội đồng được tải, sau đó mỗi trường hợp được một lớp hoàn toàn riêng biệt, mà chỉ xảy ra để có cùng tên. Do đó, hàm tạo tĩnh được gọi một lần cho mỗi hàm. Nếu bạn kiểm tra 'AssemblyQualifiedName' của họ, nó có lẽ sẽ khác. – CodesInChaos

+0

Cảm ơn lời khuyên của bạn với GetAssebmlies (AppDomain currentDomain = AppDomain.CurrentDomain; Assembly [] assems = currentDomain.GetAssemblies()). Nó giúp tôi tìm ra vấn đề là gì. Tôi đã cập nhật câu hỏi với một số phát hiện khác bao gồm một lỗi thú vị không có hại trong thời gian chạy .NET. – buckley

1

Vâng nó thể được explcitly cách gọi loại initializer:

var initializer = typeof(Foo).TypeInitializer; 
initializer.Invoke(null); 

Tuy nhiên, tôi muốn hy vọng rằng nó không làm điều đó. Bạn có thể đưa ra một chương trình ngắn nhưng đầy đủ để chứng minh điều này xảy ra không?

+0

Xin chào John, tôi sẽ cô lập nó trước đó nếu nó không phải là một phần của một giải pháp lớn. Tôi nên có và bạn có thể tìm thấy nó ở sửa # 1 trong câu hỏi của tôi – buckley

+0

Vì vậy, những gì thực sự xảy ra nếu bạn làm điều đó? .NET không quan tâm và chỉ hoạt động như thể constructor tĩnh được gọi lần đầu tiên? –

+0

@ChrisMarisic: Có, theo như tôi biết, đó là trường hợp. –

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