开发者

The as operator rejects the object even though the object appears to be of the correct type in the debugger

The following code throws an exception. If there is no easy answer or stuff to check, I'll try to produce something that reproduces the error (though I don't know where to upload it).

public static XMLobj Load(string FileName)
{
    if (File.Exis开发者_JS百科ts(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 appears to be of correct type in the quick watch. 
    IRDnet.XMLobj def2 = o as IRDnet.XMLobj; 
        // def2 is "undefined" (as operator rejected o)
    def = (IRDnet.XMLobj)o;     
        // Throws InvalidCastException with no InnerException.
    stream.Close();
    return def;
}

The strange thing is that "o" appears to be of correct type if I break just before the exception is thrown:

o {IRDnet.XMLobj} System.Object

And the object casts just fine in the quickwatch window. Values are easily inspected.

It is executed from the same project that it is part of. So, no loading contexts. FYI: the static method is part of the XMLobj class if that's relevant. Is there some other criteria for a successful cast that I'm not aware of? Any code that gets implicitly executed?

I've checked that reflector produces the equivalent code to make sure that nothing was lost in compiler optimization.

Any clues, people? I'm stumped. I even hoped that just writing this question would make me think twice on something completely obvious.


Chances are this is a versioning issue. That is, the deserialized XMLobj is a different version to the one you've compiled with. Check the fully qualified name of each type.


The .NET Serializer produces {Assembly}.Serializer.dll assemblies to speed up XML serialization/deserialization. Try to delete every Assembly and compile from scratch.

If the assemblies does not match exactly an InvalidCast Exception is throw.

EDIT: Look in your debugger output to see what assemblies have been loaded.


UPDATE:

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

produces:

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

So there is definitely a legitimate type mismatch. I highly appreciate this help. I was completely stuck. Now I have a lead. Now to find how the old type survived the rebuilding.

Maybe the XML file has something to say about it.... Or maybe it is the secretive Serialize-assembly somewhere that was mentioned....

I'm not stuck. I'm still digging, but I thought I'd inform of this new development. If anybody has more tips about interrogating a type about its declaration, then please chip in. Otherwise, thank you all!


ANSWER

The first thing to do if you ever get into this exception for seeming identical types, is to check that the two types are actually the same.

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

And then check them in the debugger. Take especially note of the "AssemblyQualifiedName". My two types turned out to be different versions of the same class.

Then do pay careful attention to the output window in Visual Studio as you are single stepping through. It will tell you when which assemblies are loaded. In my example, the culprit came in clear text in the debug output just as I stepped over the line

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

There, the debugger revealed that another, older, version of my assembly was loaded from a location that I wasn't aware of.

I neglected to tell the guys here that I debug using an external exe that loads my assembly. It turns out that the CLR, I assume on behalf of the XmlSerializer class constructor to resolve the "typeof", looks in the exe folder and its subfolders (which is what CLR does). And, lo and behold, deep down there there was a bastard of the original version of the IRDnet.dll file that I was fixing.

I still do not see how the two "typeof" statements produce different results: One results in the object type currently within context, whereas the other causes the CLR do go out looking for it in the execution folder. One possible theory is that the typeof statement is somehow lazily evalutated. I wouldn't know.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜