Hi, Jeffrey,
1) I've pasted the partial class code for a form class that, if you put into
a windows forms project and build, should demo problem (1). I've also sent
you the full project as an email attachment.
2) I haven't seen any attribute for the serializee to control versioning
serialization; like I said, it seems you have to change properties on the
formatter itself. This is a problem for me because I'm trying to use the
caching application block. Can you ask that team how they recommend to
versioning of objects cached with that block? I'd rather not change that
block, but if I do, perhaps I'll change it to use XmlSerializer (not
SoapFormatter), which seems cleaner.
Thanks for your help!
--------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace DemoDictionarySerializeIssue
{
/*
This program demonstrates the following problem:
* ---------------------------------------------------------
If you serialize non-Dictionary classes, then setting AssemblyFormat to
simple seems to cause the OptionalFieldAttribute to not be needed, AND seems
to make the deserializer not care if the assembly version changes. However,
if I serialize dictionary classes, then the deserializer requires the
assembly version to match, even if I set AssemblyFormat to simple. Is there
a way to get the rules to apply consistently?
* ---------------------------------------------------------
If we serialize dictionaries that have items as entries,
then we have a dependency on the assembly version;
If we serialize itemholder that has an item member, we don't seem to have a
dependency
on the assembly version:
1) Run the program, click on serialize, then click on deserialize. See
that it works properly
2) close the program, change the AssemblyVersion from 1 to 2 in
AssemblyInfo.cs, and rebuild
3) Run the program, click on deserialize - see the File Load exception - it
appears
that the correct assembly version couldn't be found
4) uncheck "use dictionary", click on serialize, then click on deserialize.
See that it
works properly.
5) close the program, change the AssemblyVersion from 2 to 3 in
AssemblyInfo.cs, and rebuild
6) Run the program, uncheck "use dictionary", then click on deserialize -
note that it now
works fine
*/
/// </summary>
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void m_btnSerialize_Click(object sender, EventArgs e)
{
MyDictionary dictionary = new MyDictionary();
Item item1 = new Item("entry1","one");
dictionary[item1.m_sName] = item1;
Item item2 = new Item("entry2", "two");
dictionary[item2.m_sName] = item2;
try
{
BinaryFormatter bf = new BinaryFormatter();
bf.AssemblyFormat =
System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
using (FileStream bfStream = new FileStream(m_sFileName, FileMode.Create))
{
if (m_cbUseDictionary.Checked)
{
bf.Serialize(bfStream, dictionary);
}
else
{
MyItemHolder ih1 = new MyItemHolder();
ih1.m_item = item1;
bf.Serialize(bfStream, ih1);
}
}
}
catch (Exception except)
{
MessageBox.Show(except.ToString());
}
}
private void m_btnDeserialize_Click(object sender, EventArgs e)
{
try
{
BinaryFormatter bf = new BinaryFormatter();
bf.AssemblyFormat =
System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
using (FileStream bfStream = new FileStream(m_sFileName, FileMode.Open))
{
if (m_cbUseDictionary.Checked)
{
MyDictionary dictionary = (MyDictionary)bf.Deserialize(bfStream);
Item item1 = dictionary["entry1"];
Item item2 = dictionary["entry2"];
}
else
{
MyItemHolder ih1 = (MyItemHolder)bf.Deserialize(bfStream);
Item item1 = ih1.m_item;
}
}
}
catch (Exception except)
{
MessageBox.Show(except.ToString());
}
}
private const string m_sFileName = "serialized.dat";
}
[Serializable]
public class Item
{
public Item(string sName, string sValue)
{
m_sName = sName;
m_sValue = sValue;
}
public Item()
{
}
public string m_sName;
public string m_sValue;
}
[Serializable]
public class MyDictionary : Dictionary<string, Item>
{
protected MyDictionary(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
public MyDictionary()
{
}
}
[Serializable]
public class MyItemHolder
{
public Item m_item;
}
}
[quoted text, click to view] ""Jeffrey Tan[MSFT]"" wrote:
> Hi Andy,
>
> Thanks for your feedback!
>
> > I guess they're talking about v1 in that sentence?
> Yes, I assume he is talking about .Net1.1. Also, since this article is
> written in October 2004, which .Net2.0 is still in beta version, if the
> author is talking about .Net2.0, I assume that this behavior has changed in
> RTM.
>
> > 1) Is there a way to get the rules to apply consistently?
> Sorry, I am not sure I understand you completely. Can you provided more
> information regarding the "dictionary classes", which classes in FCL do you
> refer to? Is it possible for you to provide a little sample project for us
> to reproduce this problem? Thanks
>
> > 2) Is there another way to do this,
> > perhaps some attribute I can attach to my class, rather than having to
> > interact with the formatter?
> I have performed some research in this issue and found the key point lies
> in the System.Runtime.Serialization.Formatters.Binary.ObjectReader.Bind
> method and
> System.Runtime.Serialization.Formatters.Binary.ObjectReader.FastBindToType
> method.(From Reflector), below is the code snippet:
>
> internal Type Bind(string assemblyString, string typeString)
> {
> Type type1 = null;
> if ((this.m_binder != null) && !this.IsInternalType(assemblyString,
> typeString))
> {
> type1 = this.m_binder.BindToType(assemblyString, typeString);
> }
> if (type1 == null)
> {
> type1 = this.FastBindToType(assemblyString, typeString);
> }
> return type1;
> }
>
> internal Type FastBindToType(string assemblyName, string typeName)
> {
> .....
> if (this.bSimpleAssembly)
> {
> try
> {
> ObjectReader.sfileIOPermission.Assert();
> try
> {