提交 bb570aea 编写于 作者: C CyrusNajmabadi

Small tweaks to improve serialization performance.

上级 b2715a06
......@@ -28,7 +28,7 @@ private void TestInvalidStreamVersion()
private void RoundTrip(Action<ObjectWriter> writeAction, Action<ObjectReader> readAction, bool recursive)
{
var stream = new MemoryStream();
var binder = new RecordingObjectBinder();
var binder = new ObjectBinder();
var writer = new StreamObjectWriter(stream, binder: binder, recursive: recursive);
writeAction(writer);
......@@ -53,7 +53,7 @@ private void TestRoundTrip(Action<ObjectWriter> writeAction, Action<ObjectReader
private T RoundTrip<T>(T value, Action<ObjectWriter, T> writeAction, Func<ObjectReader, T> readAction, bool recursive)
{
var stream = new MemoryStream();
var binder = new RecordingObjectBinder();
var binder = new ObjectBinder();
var writer = new StreamObjectWriter(stream, binder: binder, recursive: recursive);
writeAction(writer, value);
......@@ -83,7 +83,21 @@ private void TestRoundTrip<T>(T value, Action<ObjectWriter, T> writeAction, Func
private T RoundTripValue<T>(T value, bool recursive)
{
return RoundTrip(value, (w, v) => w.WriteValue(v), r => (T)r.ReadValue(), recursive);
return RoundTrip(value,
(w, v) =>
{
if (v != null && v.GetType().IsEnum)
{
w.WriteInt64(Convert.ToInt64((object)v));
}
else
{
w.WriteValue(v);
}
},
r => value != null && value.GetType().IsEnum
? (T)Enum.ToObject(typeof(T), r.ReadInt64())
: (T)r.ReadValue(), recursive);
}
private void TestRoundTripValue<T>(T value, bool recursive)
......@@ -142,12 +156,21 @@ public TypeWithOneMember(T value)
private TypeWithOneMember(ObjectReader reader)
{
_member = (T)reader.ReadValue();
_member = typeof(T).IsEnum
? (T)Enum.ToObject(typeof(T), reader.ReadInt64())
: (T)reader.ReadValue();
}
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteValue(_member);
if (typeof(T).IsEnum)
{
writer.WriteInt64(Convert.ToInt64(_member));
}
else
{
writer.WriteValue(_member);
}
}
Func<ObjectReader, object> IObjectReadable.GetReader() => (r) => new TypeWithOneMember<T>(r);
......@@ -644,6 +667,60 @@ public void TestUInt32Values()
TestRoundTripValue<Int32>(Int32.MaxValue);
}
[Fact]
public void TestInt64Values()
{
TestRoundTripValue<Int64>(0);
TestRoundTripValue<Int64>(1);
TestRoundTripValue<Int64>(2);
TestRoundTripValue<Int64>(3);
TestRoundTripValue<Int64>(4);
TestRoundTripValue<Int64>(5);
TestRoundTripValue<Int64>(6);
TestRoundTripValue<Int64>(7);
TestRoundTripValue<Int64>(8);
TestRoundTripValue<Int64>(9);
TestRoundTripValue<Int64>(10);
TestRoundTripValue<Int64>(-1);
TestRoundTripValue<Int64>(Byte.MinValue);
TestRoundTripValue<Int64>(Byte.MaxValue);
TestRoundTripValue<Int64>(Int16.MinValue);
TestRoundTripValue<Int64>(Int16.MaxValue);
TestRoundTripValue<Int64>(UInt16.MinValue);
TestRoundTripValue<Int64>(UInt16.MaxValue);
TestRoundTripValue<Int64>(Int32.MinValue);
TestRoundTripValue<Int64>(Int32.MaxValue);
TestRoundTripValue<Int64>(UInt32.MinValue);
TestRoundTripValue<Int64>(UInt32.MaxValue);
TestRoundTripValue<Int64>(Int64.MinValue);
TestRoundTripValue<Int64>(Int64.MaxValue);
}
[Fact]
public void TestUInt64Values()
{
TestRoundTripValue<UInt64>(0);
TestRoundTripValue<UInt64>(1);
TestRoundTripValue<UInt64>(2);
TestRoundTripValue<UInt64>(3);
TestRoundTripValue<UInt64>(4);
TestRoundTripValue<UInt64>(5);
TestRoundTripValue<UInt64>(6);
TestRoundTripValue<UInt64>(7);
TestRoundTripValue<UInt64>(8);
TestRoundTripValue<UInt64>(9);
TestRoundTripValue<UInt64>(10);
TestRoundTripValue<UInt64>(Byte.MinValue);
TestRoundTripValue<UInt64>(Byte.MaxValue);
TestRoundTripValue<UInt64>(UInt16.MinValue);
TestRoundTripValue<UInt64>(UInt16.MaxValue);
TestRoundTripValue<UInt64>(Int32.MaxValue);
TestRoundTripValue<UInt64>(UInt32.MinValue);
TestRoundTripValue<UInt64>(UInt32.MaxValue);
TestRoundTripValue<UInt64>(UInt64.MinValue);
TestRoundTripValue<UInt64>(UInt64.MaxValue);
}
[Fact]
public void TestPrimitiveMemberValues()
{
......@@ -814,15 +891,18 @@ private static void TestWritingPrimitiveValues(ObjectWriter writer)
writer.WriteValue("\uDC00\uD800"); // invalid surrogate pair
writer.WriteValue("\uD800"); // incomplete surrogate pair
writer.WriteValue(null);
writer.WriteValue(ConsoleColor.Cyan);
writer.WriteValue(EByte.Value);
writer.WriteValue(ESByte.Value);
writer.WriteValue(EShort.Value);
writer.WriteValue(EUShort.Value);
writer.WriteValue(EInt.Value);
writer.WriteValue(EUInt.Value);
writer.WriteValue(ELong.Value);
writer.WriteValue(EULong.Value);
unchecked
{
writer.WriteInt64((long)ConsoleColor.Cyan);
writer.WriteInt64((long)EByte.Value);
writer.WriteInt64((long)ESByte.Value);
writer.WriteInt64((long)EShort.Value);
writer.WriteInt64((long)EUShort.Value);
writer.WriteInt64((long)EInt.Value);
writer.WriteInt64((long)EUInt.Value);
writer.WriteInt64((long)ELong.Value);
writer.WriteInt64((long)EULong.Value);
}
writer.WriteValue(typeof(object));
writer.WriteValue(_testNow);
}
......@@ -850,15 +930,20 @@ private static void TestReadingPrimitiveValues(ObjectReader reader)
Assert.Equal("\uDC00\uD800", (String)reader.ReadValue()); // invalid surrogate pair
Assert.Equal("\uD800", (String)reader.ReadValue()); // incomplete surrogate pair
Assert.Equal(null, reader.ReadValue());
Assert.Equal(ConsoleColor.Cyan, reader.ReadValue());
Assert.Equal(EByte.Value, reader.ReadValue());
Assert.Equal(ESByte.Value, reader.ReadValue());
Assert.Equal(EShort.Value, reader.ReadValue());
Assert.Equal(EUShort.Value, reader.ReadValue());
Assert.Equal(EInt.Value, reader.ReadValue());
Assert.Equal(EUInt.Value, reader.ReadValue());
Assert.Equal(ELong.Value, reader.ReadValue());
Assert.Equal(EULong.Value, reader.ReadValue());
unchecked
{
Assert.Equal((long)ConsoleColor.Cyan, reader.ReadInt64());
Assert.Equal((long)EByte.Value, reader.ReadInt64());
Assert.Equal((long)ESByte.Value, reader.ReadInt64());
Assert.Equal((long)EShort.Value, reader.ReadInt64());
Assert.Equal((long)EUShort.Value, reader.ReadInt64());
Assert.Equal((long)EInt.Value, reader.ReadInt64());
Assert.Equal((long)EUInt.Value, reader.ReadInt64());
Assert.Equal((long)ELong.Value, reader.ReadInt64());
Assert.Equal((long)EULong.Value, reader.ReadInt64());
}
Assert.Equal(typeof(object), (Type)reader.ReadValue());
Assert.Equal(_testNow, (DateTime)reader.ReadValue());
}
......@@ -977,7 +1062,7 @@ public void TestObjectMapLimits()
instances.Add(new TypeWithTwoMembers<int, string>(i, i.ToString()));
}
var binder = new RecordingObjectBinder();
var binder = new ObjectBinder();
var writer = new StreamObjectWriter(stream, binder: binder);
// Write each instance twice. The second time around, they'll become ObjectRefs
for (int pass = 0; pass < 2; pass++)
......
......@@ -32,14 +32,12 @@
<Compile Include="DiagnosticAnalyzer\AnalyzerManager.AnalyzerExecutionContext.cs" />
<Compile Include="InternalUtilities\CommandLineUtilities.cs" />
<Compile Include="InternalUtilities\OrderedMultiDictionary.cs" />
<Compile Include="Serialization\FixedObjectBinder.cs" />
<Compile Include="Serialization\IObjectReadable.cs" />
<Compile Include="Serialization\IObjectWritable.cs" />
<Compile Include="Serialization\ObjectBinder.cs" />
<Compile Include="Serialization\ObjectData.cs" />
<Compile Include="Serialization\ObjectReader.cs" />
<Compile Include="Serialization\ObjectWriter.cs" />
<Compile Include="Serialization\RecordingObjectBinder.cs" />
<Compile Include="Serialization\StreamObjectReader.cs" />
<Compile Include="Serialization\StreamObjectWriter.cs" />
<Compile Include="Serialization\TypeKey.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
namespace Roslyn.Utilities
{
/// <summary>
/// An <see cref="ObjectBinder"/> with a fixed set of type and reader mappings.
/// </summary>
internal class FixedObjectBinder : ObjectBinder
{
private readonly ImmutableDictionary<TypeKey, Type> _typeMap;
private readonly ImmutableDictionary<Type, Func<ObjectReader, object>> _readerMap;
public FixedObjectBinder(
ImmutableDictionary<TypeKey, Type> typeMap,
ImmutableDictionary<Type, Func<ObjectReader, object>> readerMap)
{
_typeMap = typeMap ?? ImmutableDictionary<TypeKey, Type>.Empty;
_readerMap = readerMap ?? ImmutableDictionary<Type, Func<ObjectReader, object>>.Empty;
}
public static readonly FixedObjectBinder Empty = new FixedObjectBinder(null, null);
public override bool TryGetType(TypeKey key, out Type type)
{
return _typeMap.TryGetValue(key, out type);
}
public override bool TryGetTypeKey(Type type, out TypeKey key)
{
// do not let types have keys that cannot be reverse mapped.
return base.TryGetTypeKey(type, out key) && _typeMap.ContainsKey(key);
}
public override bool TryGetWriter(Object instance, out Action<ObjectWriter, Object> writer)
{
// don't let objects be written that do not have known readers.
return base.TryGetWriter(instance, out writer) && _readerMap.ContainsKey(instance.GetType());
}
public override bool TryGetReader(Type type, out Func<ObjectReader, object> reader)
{
return _readerMap.TryGetValue(type, out reader);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection;
namespace Roslyn.Utilities
{
/// <summary>
/// A type that provides object and type encoding/decoding.
/// A <see cref="ObjectBinder"/> that records runtime types and object readers during object writing so they
/// can be used to read back objects later.
/// </summary>
internal abstract class ObjectBinder
/// <remarks>
/// This binder records runtime types an object readers as a way to avoid needing to describe all serialization types up front
/// or using reflection to determine them on demand.
/// </remarks>
internal sealed class ObjectBinder
{
private readonly ConcurrentDictionary<TypeKey, Type> _typeMap =
new ConcurrentDictionary<TypeKey, Type>();
private readonly ConcurrentDictionary<Type, Func<ObjectReader, object>> _readerMap =
new ConcurrentDictionary<Type, Func<ObjectReader, object>>();
/// <summary>
/// Gets the <see cref="Type"/> corresponding to the specified <see cref="TypeKey"/>.
/// Returns false if no type corresponds to the key.
/// </summary>
public abstract bool TryGetType(TypeKey key, out Type type);
public bool TryGetType(TypeKey key, out Type type)
=> _typeMap.TryGetValue(key, out type);
public bool TryGetReader(Type type, out Func<ObjectReader, object> reader)
=> _readerMap.TryGetValue(type, out reader);
private void RecordType(Type type, TypeKey key)
{
if (type != null)
{
_typeMap.TryAdd(key, type);
}
}
private void RecordReader(object instance)
{
if (instance != null)
{
var type = instance.GetType();
var key = GetAndRecordTypeKey(type);
var readable = instance as IObjectReadable;
if (readable != null)
{
if (_readerMap.ContainsKey(type))
{
Debug.Assert(_typeMap.ContainsKey(key));
}
else
{
_readerMap.TryAdd(type, readable.GetReader());
}
}
}
}
/// <summary>
/// Gets the <see cref="TypeKey"/> for the specified <see cref="Type"/>.
/// Returns false if the type cannot be serialized.
/// </summary>
public virtual bool TryGetTypeKey(Type type, out TypeKey key)
public TypeKey GetAndRecordTypeKey(Type type)
{
key = new TypeKey(type.GetTypeInfo().Assembly.FullName, type.FullName);
return true;
var key = new TypeKey(type.GetTypeInfo().Assembly.FullName, type.FullName); ;
RecordType(type, key);
return key;
}
/// <summary>
/// Gets a function that reads an type's members from an <see cref="ObjectReader"/> and constructs an instance with those members.
/// Returns false if the type cannot be deserialized.
/// </summary>
public abstract bool TryGetReader(Type type, out Func<ObjectReader, object> reader);
private static readonly Action<ObjectWriter, object> s_writer
= (w, i) => ((IObjectWritable)i).WriteTo(w);
/// <summary>
/// Gets a function that writes an object's members to a <see cref="ObjectWriter"/>.
/// Returns false if the type cannot be serialized.
/// </summary>
public virtual bool TryGetWriter(object instance, out Action<ObjectWriter, object> writer)
{
public bool TryGetWriter(Object instance, out Action<ObjectWriter, object> writer)
{
RecordReader(instance);
if (instance is IObjectWritable)
{
writer = (w, i) => ((IObjectWritable)i).WriteTo(w); // static delegate should be cached
writer = s_writer;
return true;
}
else
......@@ -50,4 +97,4 @@ public virtual bool TryGetWriter(object instance, out Action<ObjectWriter, objec
}
}
}
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
......@@ -17,15 +18,17 @@ namespace Roslyn.Utilities
/// </remarks>
internal sealed class RecordingObjectBinder : ObjectBinder
{
private readonly ConcurrentDictionary<TypeKey, Type> _typeMap =
new ConcurrentDictionary<TypeKey, Type>();
private readonly Dictionary<TypeKey, Type> _typeMap_mustLock = new Dictionary<TypeKey, Type>();
private readonly ConcurrentDictionary<Type, Func<ObjectReader, object>> _readerMap =
new ConcurrentDictionary<Type, Func<ObjectReader, object>>();
new ConcurrentDictionary<Type, Func<ObjectReader, object>>(concurrencyLevel: 2, capacity: 64);
public override bool TryGetType(TypeKey key, out Type type)
{
return _typeMap.TryGetValue(key, out type);
lock (_typeMap_mustLock)
{
return _typeMap_mustLock.TryGetValue(key, out type);
}
}
public override bool TryGetTypeKey(Type type, out TypeKey key)
......@@ -56,7 +59,10 @@ private void RecordType(Type type, TypeKey key)
{
if (type != null)
{
_typeMap.TryAdd(key, type);
lock (_typeMap_mustLock)
{
_typeMap_mustLock[key] = type;
}
}
}
......@@ -74,7 +80,12 @@ private void RecordReader(object instance)
{
if (_readerMap.ContainsKey(type))
{
Debug.Assert(_typeMap.ContainsKey(key));
#if DEBUG
lock (_typeMap_mustLock)
{
Debug.Assert(_typeMap_mustLock.ContainsKey(key));
}
#endif
}
else
{
......
......@@ -36,14 +36,15 @@ internal sealed partial class StreamObjectReader : ObjectReader, IDisposable
internal const byte VersionByte2 = 0b00000001;
private readonly BinaryReader _reader;
private readonly ObjectBinder _binder;
private readonly ObjectBinder _binderOpt;
private readonly bool _recursive;
private readonly CancellationToken _cancellationToken;
/// <summary>
/// Map of reference id's to deserialized objects.
/// </summary>
private readonly ReferenceMap _referenceMap;
private readonly ReaderReferenceMap<object> _objectReferenceMap;
private readonly ReaderReferenceMap<string> _stringReferenceMap;
/// <summary>
/// Stack of values used to construct objects and arrays
......@@ -88,8 +89,9 @@ internal sealed partial class StreamObjectReader : ObjectReader, IDisposable
_recursive = IsRecursive(stream);
_reader = new BinaryReader(stream, Encoding.UTF8);
_referenceMap = new ReferenceMap(knownObjects);
_binder = binder ?? FixedObjectBinder.Empty;
_objectReferenceMap = new ReaderReferenceMap<object>(knownObjects);
_stringReferenceMap = new ReaderReferenceMap<string>(knownObjects);
_binderOpt = binder;
_cancellationToken = cancellationToken;
if (!_recursive)
......@@ -142,7 +144,8 @@ internal static bool IsRecursive(Stream stream)
public void Dispose()
{
_referenceMap.Dispose();
_objectReferenceMap.Dispose();
_stringReferenceMap.Dispose();
if (!_recursive)
{
......@@ -417,11 +420,14 @@ private Variant ReadVariant()
case EncodingKind.StringRef_1Byte:
case EncodingKind.StringRef_2Bytes:
return Variant.FromString(ReadStringValue(kind));
case EncodingKind.Object:
case EncodingKind.ObjectRef_4Bytes:
return Variant.FromObject(_objectReferenceMap.GetValue(_reader.ReadInt32()));
case EncodingKind.ObjectRef_1Byte:
return Variant.FromObject(_objectReferenceMap.GetValue(_reader.ReadByte()));
case EncodingKind.ObjectRef_2Bytes:
return ReadObject(kind);
return Variant.FromObject(_objectReferenceMap.GetValue(_reader.ReadUInt16()));
case EncodingKind.Object:
return ReadObject();
case EncodingKind.Type:
case EncodingKind.TypeRef_4Bytes:
case EncodingKind.TypeRef_1Byte:
......@@ -552,16 +558,16 @@ public override Object ReadValue()
/// <summary>
/// An reference-id to object map, that can share base data efficiently.
/// </summary>
private class ReferenceMap
private class ReaderReferenceMap<T> where T : class
{
private readonly ObjectData _baseData;
private readonly int _baseDataCount;
private readonly List<object> _values;
private readonly List<T> _values;
internal static readonly ObjectPool<List<object>> s_objectListPool
= new ObjectPool<List<object>>(() => new List<object>(20));
internal static readonly ObjectPool<List<T>> s_objectListPool
= new ObjectPool<List<T>>(() => new List<T>(20));
public ReferenceMap(ObjectData baseData)
public ReaderReferenceMap(ObjectData baseData)
{
_baseData = baseData;
_baseDataCount = baseData != null ? _baseData.Objects.Length : 0;
......@@ -580,18 +586,18 @@ public int GetNextReferenceId()
return _baseDataCount + _values.Count - 1;
}
public void SetValue(int referenceId, object value)
public void SetValue(int referenceId, T value)
{
_values[referenceId - _baseDataCount] = value;
}
public object GetValue(int referenceId)
public T GetValue(int referenceId)
{
if (_baseData != null)
{
if (referenceId < _baseDataCount)
{
return _baseData.Objects[referenceId];
return (T)_baseData.Objects[referenceId];
}
else
{
......@@ -645,13 +651,13 @@ private string ReadStringValue(EncodingKind kind)
switch (kind)
{
case EncodingKind.StringRef_1Byte:
return (string)_referenceMap.GetValue(_reader.ReadByte());
return _stringReferenceMap.GetValue(_reader.ReadByte());
case EncodingKind.StringRef_2Bytes:
return (string)_referenceMap.GetValue(_reader.ReadUInt16());
return _stringReferenceMap.GetValue(_reader.ReadUInt16());
case EncodingKind.StringRef_4Bytes:
return (string)_referenceMap.GetValue(_reader.ReadInt32());
return _stringReferenceMap.GetValue(_reader.ReadInt32());
case EncodingKind.StringUtf16:
case EncodingKind.StringUtf8:
......@@ -664,7 +670,7 @@ private string ReadStringValue(EncodingKind kind)
private unsafe string ReadStringLiteral(EncodingKind kind)
{
int id = _referenceMap.GetNextReferenceId();
int id = _stringReferenceMap.GetNextReferenceId();
string value;
if (kind == EncodingKind.StringUtf8)
{
......@@ -681,7 +687,7 @@ private unsafe string ReadStringLiteral(EncodingKind kind)
}
}
_referenceMap.SetValue(id, value);
_stringReferenceMap.SetValue(id, value);
return value;
}
......@@ -710,8 +716,8 @@ private Variant ReadArray(EncodingKind kind)
// SUBTLE: If it was a primitive array, only the EncodingKind byte of the element type was written, instead of encoding as a type.
var elementKind = (EncodingKind)_reader.ReadByte();
Type elementType;
if (StreamObjectWriter.s_reverseTypeMap.TryGetValue(elementKind, out elementType))
var elementType = StreamObjectWriter.s_reverseTypeMap[(int)elementKind];
if (elementType != null)
{
return Variant.FromArray(this.ReadPrimitiveTypeArrayElements(elementType, elementKind, length));
}
......@@ -758,7 +764,7 @@ private Variant ConstructArray(Type elementType, int length)
private Array ReadPrimitiveTypeArrayElements(Type type, EncodingKind kind, int length)
{
Debug.Assert(StreamObjectWriter.s_reverseTypeMap[kind] == type);
Debug.Assert(StreamObjectWriter.s_reverseTypeMap[(int)kind] == type);
// optimizations for supported array type by binary reader
if (type == typeof(byte))
......@@ -968,26 +974,26 @@ private Type ReadType(EncodingKind kind)
switch (kind)
{
case EncodingKind.TypeRef_1Byte:
return (Type)_referenceMap.GetValue(_reader.ReadByte());
return (Type)_objectReferenceMap.GetValue(_reader.ReadByte());
case EncodingKind.TypeRef_2Bytes:
return (Type)_referenceMap.GetValue(_reader.ReadUInt16());
return (Type)_objectReferenceMap.GetValue(_reader.ReadUInt16());
case EncodingKind.TypeRef_4Bytes:
return (Type)_referenceMap.GetValue(_reader.ReadInt32());
return (Type)_objectReferenceMap.GetValue(_reader.ReadInt32());
case EncodingKind.Type:
int id = _referenceMap.GetNextReferenceId();
int id = _objectReferenceMap.GetNextReferenceId();
var assemblyName = this.ReadStringValue();
var typeName = this.ReadStringValue();
Type type;
if (!_binder.TryGetType(new TypeKey(assemblyName, typeName), out type))
if (_binderOpt == null || !_binderOpt.TryGetType(new TypeKey(assemblyName, typeName), out type))
{
throw NoSerializationTypeException(typeName);
}
_referenceMap.SetValue(id, type);
_objectReferenceMap.SetValue(id, type);
return type;
default:
......@@ -1043,53 +1049,39 @@ private object ReadBoxedEnum()
throw ExceptionUtilities.UnexpectedValue(enumType);
}
private Variant ReadObject(EncodingKind kind)
private Variant ReadObject()
{
switch (kind)
{
case EncodingKind.ObjectRef_4Bytes:
return Variant.FromObject(_referenceMap.GetValue(_reader.ReadInt32()));
case EncodingKind.ObjectRef_1Byte:
return Variant.FromObject(_referenceMap.GetValue(_reader.ReadByte()));
case EncodingKind.ObjectRef_2Bytes:
return Variant.FromObject(_referenceMap.GetValue(_reader.ReadUInt16()));
int id = _objectReferenceMap.GetNextReferenceId();
case EncodingKind.Object:
int id = _referenceMap.GetNextReferenceId();
Type type = this.ReadType();
Type type = this.ReadType();
Func<ObjectReader, object> typeReader;
if (!_binder.TryGetReader(type, out typeReader))
{
throw NoSerializationReaderException(type.FullName);
}
Func<ObjectReader, object> typeReader;
if (_binderOpt == null || !_binderOpt.TryGetReader(type, out typeReader))
{
throw NoSerializationReaderException(type.FullName);
}
if (_recursive)
{
// recursive: read and construct instance immediately from member elements encoding next in the stream
var instance = typeReader(this);
_referenceMap.SetValue(id, instance);
return Variant.FromObject(instance);
}
else
{
uint memberCount = this.ReadCompressedUInt();
if (memberCount == 0)
{
return ConstructObject(type, (int)memberCount, typeReader, id);
}
else
{
// non-recursive: remember construction information to invoke later when member elements available on the stack
_constructionStack.Push(Construction.CreateObjectConstruction(type, (int)memberCount, _valueStack.Count, typeReader, id));
return Variant.None;
}
}
if (_recursive)
{
// recursive: read and construct instance immediately from member elements encoding next in the stream
var instance = typeReader(this);
_objectReferenceMap.SetValue(id, instance);
return Variant.FromObject(instance);
}
else
{
uint memberCount = this.ReadCompressedUInt();
default:
throw ExceptionUtilities.UnexpectedValue(kind);
if (memberCount == 0)
{
return ConstructObject(type, (int)memberCount, typeReader, id);
}
else
{
// non-recursive: remember construction information to invoke later when member elements available on the stack
_constructionStack.Push(Construction.CreateObjectConstruction(type, (int)memberCount, _valueStack.Count, typeReader, id));
return Variant.None;
}
}
}
......@@ -1114,7 +1106,7 @@ private Variant ConstructObject(Type type, int memberCount, Func<ObjectReader, o
throw DeserializationReadIncorrectNumberOfValuesException(type.Name);
}
_referenceMap.SetValue(id, instance);
_objectReferenceMap.SetValue(id, instance);
return Variant.FromObject(instance);
}
......
......@@ -1234,7 +1234,7 @@ public bool IsEquivalentTo(SyntaxNode node, bool topLevel = false)
return IsEquivalentToCore(node, topLevel);
}
internal static readonly ObjectBinder s_defaultBinder = new RecordingObjectBinder();
internal static readonly ObjectBinder s_defaultBinder = new ObjectBinder();
public virtual void SerializeTo(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
{
......
......@@ -260,9 +260,6 @@
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\UnicodeCharacterUtilities.cs">
<Link>InternalUtilities\UnicodeCharacterUtilities.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\Serialization\FixedObjectBinder.cs">
<Link>Serialization\FixedObjectBinder.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\Serialization\IObjectReadable.cs">
<Link>Serialization\IObjectReadable.cs</Link>
</Compile>
......@@ -281,9 +278,6 @@
<Compile Include="..\..\..\Compilers\Core\Portable\Serialization\ObjectWriter.cs">
<Link>Serialization\ObjectWriter.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\Serialization\RecordingObjectBinder.cs">
<Link>Serialization\RecordingObjectBinder.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\Serialization\StreamObjectReader.cs">
<Link>Serialization\StreamObjectReader.cs</Link>
</Compile>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册