2012-02-08 21 views
5

To pytanie dotyczy raczej języka C# niż log4net (chyba).Statyczny konstruktor jest wywoływany dwa razy w tym samym appdomain?

Utworzono niestandardowego aplikatora i pozwoliłem mu odczytywać pole statyczne ustawione wcześniej przez program.

Ku mojemu zaskoczeniu, pole statyczne zostało ponownie zainicjowane, a ustawiona wartość nie dotarła do aplikanta.

Uruchomiłem debugview i zobaczyłem, że konstruktor statyczny jest wywoływany dwa razy (!). To nie powinno być możliwe w tym samym appdomain, prawda? Tylko debugview wyłączył to, ponieważ VS nie uderzył po raz drugi w punkt przerwania.

Należy zauważyć, że nie jest to pytanie o unikanie używania zmiennej statycznej z log4net. Interesuje mnie, jakiego rodzaju magii używa log4net, aby to osiągnąć?

Edit # 1

Witaj John, Wielki fan.

Wyizolowałem go dalej zgodnie z życzeniem. Najpierw zacząłem pusto i pracowałem nad sytuacją docelową, która ujawnia błąd. Ponieważ prawie dopasowałem postać docelową do charakteru i wciąż nie poprawiałem, poszłam odwrotnie.

Począwszy od sytuacji awaryjnej, usunąłem wszystko, co uważałem za nieistotne, dopóki nie zaczęło ... działać zgodnie z oczekiwaniami.

Wydaje istnieją pewne dziwne Höing, gdy środowisko wykonawcze próbuje rozwiązane zespole log4net (jak obserwowane w trybie debugowania)

to, co widzę z DebugView:

[7756] Ogólnie: WARN - Nie można przeanalizować wersji modułu "log4net" modułu. Wyjątek: System.NullReferenceException: Odwołanie do obiektu nie jest ustawione na instancję obiektu. [7756] at DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor (String modulePath, String moduleLoadMessage, Boolean isUserCode, nazwa łańcucha, wersja String) [7756] Ogólne: WARN - Nie można przeanalizować modułu "FollowUp.Common" wersja. Wyjątek: System.NullReferenceException: Odwołanie do obiektu nie jest ustawione na instancję obiektu. [7756] w DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor (String ModulePath, String, Boolean isUserCode moduleLoadMessage, String nazwa, wersja String)

i VS przedstawia żadnej wartości dla ścieżki na ekranie debug-modułu. Jak udało mi się dojść do tej sytuacji? Dziwne, że udało mu się załadować zespół, ale nie można już stwierdzić, skąd :)

Oto sytuacja odizolowana do tego stopnia, że ​​jeśli zmienię ją dalej, zacznie działać zgodnie z oczekiwaniami.

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

ja nadal jestem zainteresowany szczegółami technicznymi, ale po usunięciu wzmianki o log4net i dodanie go ponownie wszystko zaczęło znowu działać. Cieszę się, że to działa, ale szkoda mi, że nie mam dokładnego wyjaśnienia.

Także konstruktor statyczny * jest * wywoływany dwa razy, co ma sens, ponieważ typ jest inicjowany ponownie, gdy log4net dostanie w swoje ręce na tym.

Myślę, że nie warto poświęcać więcej czasu na tę sprawę. Myślę, że rozwiązanie było w dziwnym stanie i zrozumienie tego wszystkiego ma marginalną wartość. Mimo to, jeśli możesz wymyślić coś, co to wyjaśni, chętnie bym się tutaj znalazł.

Edit # 2

Okazało się, że niektóre zespoły zostały faktycznie załadowane dwa razy w tym jeden ze statycznym konstruktorze. Zbadam później, jak to jest możliwe, ale mam obejście problemu przez wyłączenie i włączenie Costura. Costura to zadanie msbuild, które łączy wszystkie złożenia w jedno. Nie mówię, że Costura jest przyczyną. Łatwo może być, że pliki csproj/sln były w dziwnym stanie.

Zastanawiając się, jak zdiagnozować ten problem szybciej w przyszłości uruchomiłem sysinternals ProcessExplorer. Teraz spodziewałem się zobaczyć, że zespoły są ładowane tylko raz, ale zauważyłem, że zostały załadowane dwa razy. Wygląda na to jest błąd w czasie wykonywania ów stały tylko w .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 -adres-spacja-dwukrotne

Edytuj # 3 Costura sprawił, że zespoły wczytały się dwa razy. Problem został rozwiązany tego samego dnia przez właściciela projektu :) http://code.google.com/p/costura/issues/detail?id=17&thanks=17&ts=1328826304

Potrzebujemy tagu Costura, ale nie mam wymaganych 1500 punktów reputacji. Utwórz go, jeśli masz prawa. Dzięki.

poważaniem, Tom

+1

"Tylko debugview wyłączył to, ponieważ VS nie trafił po raz drugi w punkcie przerwania." <--- Głosuję za błędem w debugview jako bardziej prawdopodobną przyczyną tego problemu. Jestem naprawdę ciekawa, co naprawdę się tam stało :) – dasblinkenlight

+0

Witaj dasblinkenlight. Debugview jest czystym obserwatorem, nie widzę, aby generował on jakiekolwiek efekty uboczne. Jeśli debugowanie uruchomi śledzenie.Writeline dwa razy oznacza to, że kod został wykonany dwukrotnie, a debugview nie miał z tym nic wspólnego. – buckley

+1

To się nie stało, twarda i twarda gwarancja. Zapomnienie o usunięciu domyślny program nasłuchujący śledzenia jest częstym błędem. –

Odpowiedz

4

Wygląda na to, że udało się załadować dwa osobne wystąpienia log4net do tego samego AppDomain.

Jeden referencje projektu:

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

Drugi:

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

Jednym z nich jest silnie nazwane, a drugi nie, to spowodowało .NET dając im różne tożsamości. Ścieżka wskazówek również się różni. Również jeden wydaje się być 1.2.10, drugi 1.2.11.

Spróbuj zadzwonić pod numer AppDomain.GetAssemblies() i sprawdzić, czy log4net występuje dwukrotnie.

+0

Witaj CodeInChaos. Dziękuję za wskazanie tego, a zwłaszcza wyjaśnienie, dlaczego jest to możliwe. Czy wiesz również, dlaczego to powoduje, że konstruktor statyczny (a tym samym inicjalizacja pola statycznego) jest wywoływana dwa razy? Są w tej samej appdomainu, więc oczekuję, że podzielą się statycznymi. – buckley

+3

Po załadowaniu dwóch wystąpień złożenia, każda z nich otrzymuje całkowicie oddzielne klasy, które po prostu mają tę samą nazwę. W ten sposób konstruktor statyczny zostaje wywołany raz dla każdego z nich. Jeśli sprawdzisz ich "AssemblyQualifiedName", prawdopodobnie będzie inaczej. – CodesInChaos

+0

Dzięki za wskazówkę z GetAssebmlies (AppDomain currentDomain = AppDomain.CurrentDomain; Assembly [] assems = currentDomain.GetAssemblies()). Pomógł mi znaleźć problem. Zaktualizowałem to pytanie, dodając kilka dodatkowych informacji, w tym interesujący, nieszkodliwy błąd w środowisku wykonawczym .NET. – buckley

1

Dobrze mógłby być explcitly powołując typ inicjatora:

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

Jednak ja bym nadzieję, że nie robi tego. Czy możesz wymyślić krótki, ale kompletny program, który pokazuje, że tak się dzieje?

+0

Witaj, John, wyizolowałbym go wcześniej, gdyby nie był częścią dużego rozwiązania. Powinienem to zrobić i możesz go znaleźć w edytorze nr 1 w moim pytaniu – buckley

+0

Co się właściwie dzieje, jeśli to zrobisz? .NET nie obchodzi i działa tak, jakby po raz pierwszy wywołano konstruktor statyczny? –

+0

@ChrisMarisic: Tak, o ile wiem, tak jest. –

Powiązane problemy