2 Stimmen

Der as-Operator lehnt das Objekt ab, obwohl es im Debugger den Anschein hat, dass das Objekt den richtigen Typ hat.

Der folgende Code wirft eine Ausnahme. Wenn es keine einfache Antwort oder Dinge zu überprüfen gibt, werde ich versuchen, etwas zu produzieren, das den Fehler reproduziert (obwohl ich nicht weiß, wo ich es hochladen soll).

public static XMLobj Load(string FileName)
{
    if (File.Exists(FileName) == false)
    {
            return null;
    }
    IRDnet.XMLobj def;
    XmlSerializer xmlser = new XmlSerializer(typeof(IRDnet.XMLobj));
    System.IO.Stream stream = File.OpenRead(FileName);
    object o = xmlser.Deserialize(stream);   
        // o scheint im Quickwatch vom richtigen Typ zu sein.
    IRDnet.XMLobj def2 = o as IRDnet.XMLobj; 
        // def2 ist "undefiniert" (da der Operator o abgelehnt hat)
    def = (IRDnet.XMLobj)o;     
        // Wirft InvalidCastException ohne InnerException.
    stream.Close();
    return def;
}

Das Seltsame daran ist, dass "o" als korrekter Typ erscheint, wenn ich kurz vor dem Auswerfen der Ausnahme anhalte:

o {IRDnet.XMLobj} System.Object

Und das Objekt lässt sich problemlos im Quickwatch-Fenster umwandeln. Werte können problemlos inspiziert werden.

Es wird aus demselben Projekt ausgeführt, zu dem es gehört. Also keine Ladevorgänge. FYI: Die statische Methode ist Teil der Klasse XMLobj, falls das relevant ist. Gibt es vielleicht andere Kriterien für eine erfolgreiche Umwandlung, von denen ich nicht weiß? Wird irgendwelcher Code implizit ausgeführt?

Ich habe überprüft, ob Reflector den äquivalenten Code erzeugt, um sicherzustellen, dass durch Compileroptimierung nichts verloren gegangen ist.

Irgendwelche Hinweise, Leute? Ich bin ratlos. Ich habe sogar gehofft, dass nur das Schreiben dieser Frage mich dazu bringen würde, noch einmal über etwas komplett Offensichtliches nachzudenken.

2voto

Kent Boogaart Punkte 170094

Möglicherweise handelt es sich hier um ein Versionsproblem. Das deserialisierte XMLobj ist wahrscheinlich eine andere Version als die, mit der Sie kompiliert haben. Überprüfen Sie den vollständig qualifizierten Namen jedes Typs.

1voto

Arthur Punkte 7771

Der .NET Serializer erstellt {Assembly}.Serializer.dll Assemblys, um die XML Serialisierung/Deserialisierung zu beschleunigen. Versuchen Sie, jede Assembly zu löschen und neu zu kompilieren.

Wenn die Assemblys nicht genau übereinstimmen, wird eine InvalidCast Exception ausgelöst.

BEARBEITEN: Sehen Sie im Debugger-Output nach, welche Assemblys geladen wurden.

1voto

Tormod Punkte 4245

UPDATE:

        string tmp = o.GetType().AssemblyQualifiedName;
        string tmp2 = typeof(XMLobj).AssemblyQualifiedName;

ergibt:

tmp "IRDnet.XMLobj, IRDnet, Version=1.0.3600.18887, Culture=neutral, PublicKeyToken=null" string tmp2 "IRDnet.XMLobj, IRDnet, Version=1.0.3601.27699, Culture=neutral, PublicKeyToken=null" string

Es besteht definitiv ein legitimer Typen-Missmatch. Ich schätze diese Hilfe sehr. Ich war komplett festgefahren. Jetzt habe ich eine Spur. Jetzt muss ich herausfinden, wie der alte Typ das Neukompilieren überlebt hat.

Vielleicht hat die XML-Datei etwas dazu zu sagen.... Oder vielleicht ist es das geheime Serialize-Assembly irgendwo, von dem die Rede war....

Ich stecke nicht fest. Ich grabe immer noch, aber ich dachte, ich informiere über diese neue Entwicklung. Falls jemand weitere Tipps zum Befragen eines Typs bezüglich seiner Deklaration hat, dann bitte melden. Ansonsten vielen Dank an alle!

0voto

Tormod Punkte 4245

ANTWORT

Das erste, was zu tun ist, wenn Sie jemals diese Exception für scheinbar identische Typen erhalten, ist zu überprüfen, ob die beiden Typen tatsächlich gleich sind.

System.Type t1 = typeof(XMLobj); 
System.Type t2 = o.GetType(); 

Und überprüfen Sie sie dann im Debugger. Achten Sie besonders auf den "AssemblyQualifiedName". Meine beiden Typen stellten sich als unterschiedliche Versionen derselben Klasse heraus.

Dann achten Sie besonders auf das Ausgabefenster in Visual Studio, während Sie einzelne Schritte durchlaufen. Es wird Ihnen mitteilen, wann welche Assemblys geladen sind. In meinem Beispiel wurde der Übeltäter klar im Debug-Ausgang angezeigt, gerade als ich über die Zeile schritt

XmlSerializer xmlser = new XmlSerializer(typeof(IRDnet.XMLobj));

Dort enthüllte der Debugger, dass eine andere, ältere Version meiner Assembly aus einem Ort geladen wurde, von dem ich nichts wusste.

Ich habe versäumt, den Leuten hier zu sagen, dass ich mit einer externen exe debugge, die meine Assembly lädt. Es stellte sich heraus, dass der CLR, ich nehme an im Namen des XmlSerializer-Klassenkonstruktors zur Auflösung des "typeof", im exe-Ordner und seinen Unterordnern (was der CLR macht) sucht. Und siehe da, ganz unten gab es einen Bastard der Originalversion der IRDnet.dll-Datei, die ich reparierte.

Ich sehe immer noch nicht, wie die beiden "typeof"-Anweisungen unterschiedliche Ergebnisse liefern: Eine ergibt den Objekttyp, der sich derzeit im Kontext befindet, während die andere dazu führt, dass der CLR danach im Ausführungsordner sucht. Eine mögliche Theorie ist, dass die typeof-Anweisung irgendwie träge evaluiert wird. Ich würde es nicht wissen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X