Fix incompatibility with .NET's serialization of ObservableCollection - part of bug...
authorNeale <neale@sinenomine.net>
Thu, 18 Apr 2013 15:25:03 +0000 (11:25 -0400)
committerNeale <neale@sinenomine.net>
Thu, 18 Apr 2013 15:25:03 +0000 (11:25 -0400)
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: