From 828a6a4f45702a1a2fc27e1d5ab6d24ccefdec71 Mon Sep 17 00:00:00 2001 From: Neale Date: Thu, 18 Apr 2013 11:25:03 -0400 Subject: [PATCH] Fix incompatibility with .NET's serialization of ObservableCollection - part of bug 11294 --- .../ObservableCollection.cs | 25 ++++++---- .../ObservableCollection.cs | 8 ++-- .../CodeGenerator.cs | 17 +++++++ .../ObjectWriter.cs | 46 +++++++++++++++++-- 4 files changed, 78 insertions(+), 18 deletions(-) diff --git a/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs b/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs index 6c26e8795f6..32926907e21 100644 --- a/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs +++ b/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs @@ -40,30 +40,33 @@ namespace System.Collections.ObjectModel #endif public class ObservableCollection : Collection, 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."); } diff --git a/mcs/class/WindowsBase/System.Collections.ObjectModel/ObservableCollection.cs b/mcs/class/WindowsBase/System.Collections.ObjectModel/ObservableCollection.cs index 1ea166cd9ac..bcc4440e109 100644 --- a/mcs/class/WindowsBase/System.Collections.ObjectModel/ObservableCollection.cs +++ b/mcs/class/WindowsBase/System.Collections.ObjectModel/ObservableCollection.cs @@ -44,7 +44,7 @@ namespace System.Collections.ObjectModel public class ObservableCollection : Collection, 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; } } } diff --git a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGenerator.cs b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGenerator.cs index fd38471644b..671c196163e 100644 --- a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGenerator.cs +++ b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGenerator.cs @@ -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); diff --git a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs index 9d3c42bbd19..c5bf658a1c8 100644 --- a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs +++ b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs @@ -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: -- 2.25.1