When .NET serializes it will use the TypeForwardedFrom information when
authorNeale <neale@sinenomine.net>
Wed, 17 Apr 2013 02:27:47 +0000 (22:27 -0400)
committerNeale <neale@sinenomine.net>
Wed, 17 Apr 2013 02:27:47 +0000 (22:27 -0400)
writing Assembly information but Mono does not. This means that
serialized objects created on one platform are not able to be
deserialized on the other, thus preventing interoperability between .NET
and mono applications. Fixes the ObservableCollection part of bugzilla
11294.

mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs
mcs/class/WindowsBase/System.Collections.ObjectModel/ObservableCollection.cs
mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGenerator.cs
mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs

index 6c26e8795f62cf037c1eddafeec9a8dd8ce73aa3..32926907e2167c199c04d9c7d7d332221e4e31d2 100644 (file)
@@ -40,30 +40,33 @@ namespace System.Collections.ObjectModel
 #endif
        public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged {
                [Serializable]
-               sealed class Reentrant : IDisposable {
-                       private int count = 0;
+#if !MOBILE
+       [TypeForwardedFrom (Consts.WindowsBase_3_0)]
+#endif
+               sealed class SimpleMonitor : IDisposable {
+                       private int _busyCount = 0;
 
-                       public Reentrant()
+                       public SimpleMonitor()
                        {
                        }
 
                        public void Enter()
                        {
-                               count++;
+                               _busyCount++;
                        }
 
                        public void Dispose()
                        {
-                               count--;
+                               _busyCount--;
                        }
 
                        public bool Busy
                        {
-                               get { return count > 0; }
+                               get { return _busyCount > 0; }
                        }
                }
 
-               private Reentrant reentrant = new Reentrant ();
+               private SimpleMonitor _monitor = new SimpleMonitor ();
 
                public ObservableCollection ()
                {
@@ -83,7 +86,9 @@ namespace System.Collections.ObjectModel
                {
                }
 
+               [field:NonSerializedAttribute()]
                public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
+               [field:NonSerializedAttribute()]
                protected virtual event PropertyChangedEventHandler PropertyChanged;
 
                event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
@@ -93,8 +98,8 @@ namespace System.Collections.ObjectModel
 
                protected IDisposable BlockReentrancy ()
                {
-                       reentrant.Enter ();
-                       return reentrant;
+                       _monitor.Enter ();
+                       return _monitor;
                }
 
                protected void CheckReentrancy ()
@@ -102,7 +107,7 @@ namespace System.Collections.ObjectModel
                        NotifyCollectionChangedEventHandler eh = CollectionChanged;
 
                        // Only have a problem if we have more than one event listener.
-                       if (reentrant.Busy && eh != null && eh.GetInvocationList ().Length > 1)
+                       if (_monitor.Busy && eh != null && eh.GetInvocationList ().Length > 1)
                                throw new InvalidOperationException ("Cannot modify the collection while reentrancy is blocked.");
                }
 
index 1ea166cd9ac3134a1165f5513852e53a8112fb9d..bcc4440e109d423770f5977678b1e59dad6e8187 100644 (file)
@@ -44,7 +44,7 @@ namespace System.Collections.ObjectModel
        public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged {
                
                private class Reentrant : IDisposable {
-                       private int count = 0;
+                       private int _busyCount = 0;
 
                        public Reentrant()
                        {
@@ -52,17 +52,17 @@ namespace System.Collections.ObjectModel
 
                        public void Enter()
                        {
-                               count++;
+                               _busyCount++;
                        }
 
                        public void Dispose()
                        {
-                               count--;
+                               _busyCount--;
                        }
 
                        public bool Busy
                        {
-                               get { return count > 0; }
+                               get { return _busyCount > 0; }
                        }
                }
 
index fd38471644b2d7ec9f2e23c0e5273b920ceb9dac..671c196163e08ad69c39a05bf664164bfdbc25ac 100644 (file)
@@ -115,8 +115,13 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        // EMIT ow.WriteAssembly (writer, memberType.Assembly);
                                        gen.Emit (OpCodes.Ldarg_1);
                                        gen.Emit (OpCodes.Ldarg_2);
+#if NET_4_0
+                                       EmitLoadType (gen, memberType);
+                                       gen.EmitCall (OpCodes.Callvirt, typeof(ObjectWriter).GetMethod("WriteTypeAssembly"), null);
+#else
                                        EmitLoadTypeAssembly (gen, memberType, field.Name);
                                        gen.EmitCall (OpCodes.Callvirt, typeof(ObjectWriter).GetMethod("WriteAssembly"), null);
+#endif
                                        gen.Emit (OpCodes.Pop);
                                }
                        }
@@ -292,8 +297,14 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        // EMIT writer.Write ((int)ow.GetAssemblyId (type.Assembly));
                                        gen.Emit (OpCodes.Ldarg_2);
                                        gen.Emit (OpCodes.Ldarg_1);
+#if NET_4_0
+                                       EmitLoadType (gen, type);
+                                       gen.EmitCall (OpCodes.Callvirt, typeof(GetForwardedAttribute).GetMethod("GetAssemblyName"), null);
+                                       gen.EmitCall (OpCodes.Callvirt, typeof(ObjectWriter).GetMethod("GetAssemblyNameId"), null);
+#else
                                        EmitLoadTypeAssembly (gen, type, member);
                                        gen.EmitCall (OpCodes.Callvirt, typeof(ObjectWriter).GetMethod("GetAssemblyId"), null);
+#endif
                                        gen.Emit (OpCodes.Conv_I4);
                                        EmitWrite (gen, typeof(int));
                                        break;
@@ -318,6 +329,12 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        gen.EmitCall (OpCodes.Callvirt, typeof(Type).GetProperty("Assembly").GetGetMethod(), null);
                }
                
+               static void EmitLoadType (ILGenerator gen, Type type)
+               {
+                       gen.Emit (OpCodes.Ldtoken, type);
+                       gen.EmitCall (OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null);
+               }
+               
                static void EmitWrite (ILGenerator gen, Type type)
                {
                        gen.EmitCall (OpCodes.Callvirt, typeof(BinaryWriter).GetMethod("Write", new Type[] { type }), null);
index 9d3c42bbd19d6e3c85134a0c2639f20adc501bcc..c5bf658a1c8ece4466957625fd9eb24df61bbc42 100644 (file)
@@ -35,9 +35,25 @@ using System.Runtime.Serialization;
 using System.Runtime.Remoting.Messaging;
 using System.Reflection;
 using System.Globalization;
+using System.Runtime.CompilerServices;
 
 namespace System.Runtime.Serialization.Formatters.Binary
 {
+#if NET_4_0
+       public class GetForwardedAttribute
+       {
+               public static string GetAssemblyName (Type self) 
+               {
+                       var attrs = self.GetCustomAttributes(
+                                       typeof (TypeForwardedFromAttribute), false);
+                       if (attrs.Length == 0)
+                               return self.Assembly.FullName;
+                       else
+                               return ((TypeForwardedFromAttribute)attrs [0]).AssemblyFullName;
+               }
+       }
+#endif
+
        abstract class TypeMetadata
        {
                public string TypeAssemblyName;
@@ -73,7 +89,11 @@ namespace System.Runtime.Serialization.Formatters.Binary
                {
                        InstanceType = instanceType;
                        InstanceTypeName = instanceType.FullName;
+#if NET_4_0
+                       TypeAssemblyName = GetForwardedAttribute.GetAssemblyName(instanceType);
+#else
                        TypeAssemblyName = instanceType.Assembly.FullName;
+#endif
                }
                
                public override bool RequiresTypes {
@@ -102,7 +122,11 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        }
 
                        TypeAssemblyName = info.AssemblyName;
+#if NET_4_0
+                       InstanceTypeName = GetForwardedAttribute.GetAssemblyName(itype);
+#else
                        InstanceTypeName = info.FullTypeName;
+#endif
                }
                
                public override bool IsCompatible (TypeMetadata other)
@@ -129,7 +153,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                while (type.IsArray) 
                                        type = type.GetElementType();
                                        
-                               ow.WriteAssembly (writer, type.Assembly);
+                               ow.WriteTypeAssembly (writer, type);
                        }
                }
                
@@ -142,7 +166,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                writer.Write (name);
 
                        // Types of fields
-                       foreach (Type type in types)
+                       foreach (Type type in types) 
                                ObjectWriter.WriteTypeCode (writer, type);
 
                        // Type specs of fields
@@ -181,7 +205,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                while (type.IsArray) 
                                        type = type.GetElementType();
                                        
-                               ow.WriteAssembly (writer, type.Assembly);
+                               ow.WriteTypeAssembly (writer, type);
                        }
                }
                
@@ -511,7 +535,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
 
                        var tag = GetTypeTag (elementType);
                        if ((tag != TypeTag.ArrayOfObject) && (tag != TypeTag.ArrayOfString) && (tag != TypeTag.ArrayOfPrimitiveType))
-                               WriteAssembly (writer, elementType.Assembly);
+                               WriteTypeAssembly (writer, elementType);
 
                        // Writes the array
 
@@ -809,6 +833,15 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        writer.Write (str);
                }
 
+               public int WriteTypeAssembly (BinaryWriter writer, Type aType)
+               {
+#if NET_4_0
+                       return WriteAssemblyName (writer, GetForwardedAttribute.GetAssemblyName(aType));
+#else
+                       return WriteAssemblyName (writer, aType.Assembly.FullName);
+#endif
+               }
+               
                public int WriteAssembly (BinaryWriter writer, Assembly assembly)
                {
                        return WriteAssemblyName (writer, assembly.FullName);
@@ -994,7 +1027,12 @@ namespace System.Runtime.Serialization.Formatters.Binary
 
                                case TypeTag.GenericType:
                                        writer.Write (type.FullName);
+#if NET_4_0
+                                       string asmName = GetForwardedAttribute.GetAssemblyName(type);
+                                       writer.Write ((int) GetAssemblyNameId (asmName));
+#else
                                        writer.Write ((int)GetAssemblyId (type.Assembly));
+#endif
                                        break;
 
                                case TypeTag.ArrayOfPrimitiveType: