public static Checksum Create(WellKnownSynchronizationKind kind, IObjectWritable @object) { using var stream = SerializableBytes.CreateWritableStream(); using var objectWriter = new ObjectWriter(stream); objectWriter.WriteInt32((int)kind); @object.WriteTo(objectWriter); return(Create(stream)); }
private void WriteObject(object instance) { _cancellationToken.ThrowIfCancellationRequested(); // write object ref if we already know this instance if (_objectReferenceMap.TryGetReferenceId(instance, out int id)) { Debug.Assert(id >= 0); if (id <= byte.MaxValue) { _writer.Write((byte)EncodingKind.ObjectRef_1Byte); _writer.Write((byte)id); } else if (id <= ushort.MaxValue) { _writer.Write((byte)EncodingKind.ObjectRef_2Bytes); _writer.Write((ushort)id); } else { _writer.Write((byte)EncodingKind.ObjectRef_4Bytes); _writer.Write(id); } } else { IObjectWritable writable = instance as IObjectWritable; if (writable == null) { throw NoSerializationWriterException($"{instance.GetType()} must implement {nameof(IObjectWritable)}"); } int oldDepth = _recursionDepth; _recursionDepth++; if (_recursionDepth % MaxRecursionDepth == 0) { // If we're recursing too deep, move the work to another thread to do so we // don't blow the stack. 'LongRunning' ensures that we get a dedicated thread // to do this work. That way we don't end up blocking the threadpool. Task task = Task.Factory.StartNew( () => WriteObjectWorker(instance, writable), _cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); task.Wait(_cancellationToken); } else { WriteObjectWorker(instance, writable); } _recursionDepth--; Debug.Assert(_recursionDepth == oldDepth); } }
public void WriteValue(IObjectWritable value) { if (value == null) { _writer.Write((byte)EncodingKind.Null); return; } WriteObject(instance: value, instanceAsWritableOpt: value); }
public static Checksum Create(IObjectWritable @object, string kind) { using (var stream = SerializableBytes.CreateWritableStream()) using (var objectWriter = new StreamObjectWriter(stream)) { objectWriter.WriteString(kind); @object.WriteTo(objectWriter); return(Create(stream)); } }
private void WriteObjectWorker(IObjectWritable writable) { // emit object header up front _objectReferenceMap.Add(writable); _writer.Write((byte)EncodingKind.Object); // Directly write out the type-id for this object. i.e. no need to write out the 'Type' // tag since we just wrote out the 'Object' tag this.WriteInt32(_binderSnapshot.GetTypeId(writable.GetType())); writable.WriteTo(this); }
private void WriteWritableObject(IObjectWritable instance) { _writer.Write((byte)DataKind.Object_W); Type type = instance.GetType(); this.WriteType(type); _binder?.Record(instance); instance.WriteTo(this); }
private void WriteObject(object instance, IObjectWritable instanceAsWritableOpt) { Debug.Assert(instance != null); Debug.Assert(instanceAsWritableOpt == null || instance == instanceAsWritableOpt); _cancellationToken.ThrowIfCancellationRequested(); // write object ref if we already know this instance if (_objectReferenceMap.TryGetReferenceId(instance, out var id)) { Debug.Assert(id >= 0); if (id <= byte.MaxValue) { _writer.Write((byte)EncodingKind.ObjectRef_1Byte); _writer.Write((byte)id); } else if (id <= ushort.MaxValue) { _writer.Write((byte)EncodingKind.ObjectRef_2Bytes); _writer.Write((ushort)id); } else { _writer.Write((byte)EncodingKind.ObjectRef_4Bytes); _writer.Write(id); } } else { var writable = instanceAsWritableOpt; if (writable == null) { writable = instance as IObjectWritable; if (writable == null) { throw NoSerializationWriterException($"{instance.GetType()} must implement {nameof(IObjectWritable)}"); } } var oldDepth = _recursionDepth; _recursionDepth++; if (_recursionDepth % MaxRecursionDepth == 0) { // If we're recursing too deep, move the work to another thread to do so we // don't blow the stack. 'LongRunning' ensures that we get a dedicated thread // to do this work. That way we don't end up blocking the threadpool. var task = Task.Factory.StartNew( obj => WriteObjectWorker((IObjectWritable)obj), writable, _cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); // We must not proceed until the additional task completes. After returning from a write, the underlying // stream providing access to raw memory will be closed; if this occurs before the separate thread // completes its write then an access violation can occur attempting to write to unmapped memory. // // CANCELLATION: If cancellation is required, DO NOT attempt to cancel the operation by cancelling this // wait. Cancellation must only be implemented by modifying 'task' to cancel itself in a timely manner // so the wait can complete. task.GetAwaiter().GetResult(); } else { WriteObjectWorker(writable); } _recursionDepth--; Debug.Assert(_recursionDepth == oldDepth); } }
private void WriteWritableObject(IObjectWritable instance) { writer.Write((byte)DataKind.Object_W); Type type = instance.GetType(); this.WriteType(type); if (this.binder != null) { this.binder.Record(instance); } instance.WriteTo(this); }
public static void WriteTo(this IObjectWritable @object, ObjectWriter writer) => @object.WriteTo(writer);
private void WriteObjectWorker(object instance, IObjectWritable writable) { // emit object header up front this.WriteObjectHeader(instance, 0); writable.WriteTo(this); }