views:

175

answers:

1

Is it possible to serialize an object that is created through reflection? I get an error of "Unable to cast object of type 'testNameSpace.ScreenClass' to type 'testNameSpace.ScreenClass'" when attemping to perform the serialization of the object that was created through reflection. The error does not make sense since the types are identical so a cast should be successful. The an instance of the object created without reflection can be serialized OK.

Edit: Here is code the which did not get rendered correctly in my original post

//Get the Assembly from file
 Assembly webAssembly = Assembly.LoadFile(@"C:\TestAssembly.exe");

 //Get the type from assembly
 Type screenType = webAssembly.GetType("testNameSpace.ScreenClass");

 //get the Constructor for the type (constructor does not take in parameters)
 ConstructorInfo ctor = screenType.GetConstructor(new Type[0]);

 //create an instance of the type
 object screen = ctor.Invoke(new object[] { });

 //get the "id" property of type
 PropertyInfo screenId = screenType.GetProperty("id");

 //populate the "id" property of the instance
 screenId.SetValue(screen, "1", null);

 Console.WriteLine("value of id property: " 
  + (string)screenId.GetValue(screen,null));

 //Attempt to serialize the instance of the object created through reflection
 try
 {
  FileStream fs = new FileStream("serialized.xml", FileMode.Create);
  XmlSerializer serializer = 
   new XmlSerializer(typeof(testNameSpace.ScreenClass));
  serializer.Serialize(fs, screen); //error occurs here
  fs.Close();
 }
 catch (Exception ex)
 {
  Console.WriteLine("Message: {0}\nInnerException: {1}\nStack Trace:\n{2}", 
   ex.Message, ex.InnerException.Message, ex.StackTrace);
 }

 //Now create instance of object without using reflection and serialize
 testNameSpace.ScreenClass screen2 = new testNameSpace.ScreenClass();
 screen2.id = "2";
 FileStream fs = new FileStream("serialized2.xml", FileMode.Create);
 XmlSerializer serializer 
  = new XmlSerializer(typeof(testNameSpace.ScreenClass));
 serializer.Serialize(fs, screen2);
 fs.Close();
 Console.WriteLine
  ("\nContents of serialized2.xml:\n" + File.ReadAllText("serialized2.xml"));

Output when run from console

Message: There was an error generating the XML document.
InnerException: Unable to cast object of type 'testNameSpace.ScreenClass' to type 'testNameSpace.ScreenClass'.
Stack Trace:
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o, XmlSerializerNamespaces namespaces)
   at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o)
   at Program.GetOneProperty() in C:\Code\Serialize.cs:line 96

Contents of serialized2.xml:
<?xml version="1.0"?>
<applicationScreensScreen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="2" />
+1  A: 

The Assembly.LoadFile() method is your problem, it loads the assembly in the wrong context. Loading contexts are a bit hard to grok, Suzanne Cook talks about it in her blog. When the serializer needs the type, it will use Assembly.LoadFrom() and load the assembly again. Now it finds a mismatch, types from different assemblies are never the same.

LoadFile() is only useful in very limited scenarios, as documented in the Remarks section of the MSDN library article. You should use Assembly.LoadFrom() or Load() instead. Prefer the latter as it eliminates the possibility that an assembly with the same display name will be loaded from different files. If that causes trouble because the assembly is not in the program's probing path (it won't be if it is stored in c:\) then implement the AppDomain.AssemblyResolve event handler to ensure the correct file is found.

Hans Passant
Recipe for avoiding .NET assembly load problems: (1) Use Assembly.Load; (2) Use Assembly.LoadFrom if you're sure you need it; (3) Never use Assembly.LoadFile
Tim Robinson
Thanks for cleaning up my original post. I was not seeing a way to edit the mistakes in a post after submitting it. There obviously is a way to do this I'm just not seeing.I was able to get past the problem while still using Assembly.LoadFile. If I pass an an instance of the object instead the type then the serialization occured. XmlSerializer serializer = new XmlSerializer(typeof(testNameSpace.ScreenClass)); //errorXmlSerializer serializer = new XmlSerializer(typeof(screen)); //works
JoeT