Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / clr / src / BCL / System / Runtime / Serialization / ObjectManager.cs / 1 / ObjectManager.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: ObjectManager
**
**
** Purpose:
**
**
============================================================*/
namespace System.Runtime.Serialization {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Cache;
using System.Runtime.Remoting;
using System.Security.Permissions;
using System.Security;
using System.Runtime.Remoting.Messaging;
using System.Globalization;
[System.Runtime.InteropServices.ComVisible(true)]
public class ObjectManager {
private const int DefaultInitialSize=16;
private const int MaxArraySize=0x1000; //MUST BE A POWER OF 2!
private const int ArrayMask = MaxArraySize-1;
private const int MaxReferenceDepth = 100;
private DeserializationEventHandler m_onDeserializationHandler;
private SerializationEventHandler m_onDeserializedHandler;
private static Type[] SIConstructorTypes;
#if !FEATURE_PAL
private static Type TypeOfWindowsIdentity;
private static Type[] SIWindowsIdentityConstructorTypes;
#endif
internal ObjectHolder [] m_objects;
internal Object m_topObject = null;
internal ObjectHolderList m_specialFixupObjects; //This is IObjectReference, ISerializable, or has a Surrogate.
internal long m_fixupCount;
internal ISurrogateSelector m_selector;
internal StreamingContext m_context;
bool m_isCrossAppDomain;
public ObjectManager(ISurrogateSelector selector, StreamingContext context) : this(selector, context, true, false) {
}
internal ObjectManager(ISurrogateSelector selector, StreamingContext context, bool checkSecurity, bool isCrossAppDomain) {
if (checkSecurity) {
CodeAccessPermission.DemandInternal(PermissionType.SecuritySerialization);
}
m_objects = new ObjectHolder[DefaultInitialSize];
m_selector = selector;
m_context = context;
m_isCrossAppDomain = isCrossAppDomain;
}
private bool CanCallGetType(Object obj) {
if (RemotingServices.IsTransparentProxy(obj)) {
return false;
}
return true;
}
internal Object TopObject {
set {
m_topObject = value;
}
get {
return m_topObject;
}
}
internal ObjectHolderList SpecialFixupObjects {
get {
if (m_specialFixupObjects==null) {
m_specialFixupObjects = new ObjectHolderList();
}
return m_specialFixupObjects;
}
}
static ObjectManager() {
SIConstructorTypes = new Type[2];
SIConstructorTypes[0] = typeof(SerializationInfo);
SIConstructorTypes[1] = typeof(StreamingContext);
#if !FEATURE_PAL
TypeOfWindowsIdentity = typeof(System.Security.Principal.WindowsIdentity);
SIWindowsIdentityConstructorTypes = new Type[1];
SIWindowsIdentityConstructorTypes[0] = typeof(SerializationInfo);
#endif
}
/*==================================FindObject==================================
**Action: An internal-only function to find the object with id objectID.
**This function does no error checking, it assumes that all of that has been done already.
**Returns: The ObjectHolder for objectID or null if it doesn't exist.
**Arguments: objectID -- The objectID of the Object for which we're searching.
**Exceptions: None. This is internal only.
**Callers should verify that objectID is greater than 0.
==============================================================================*/
internal ObjectHolder FindObjectHolder(long objectID) {
BCLDebug.Assert(objectID>0,"objectID>0");
//The index of the bin in which we live is rightmost n bits of the objectID.
int index = (int)(objectID & ArrayMask);
if (index>=m_objects.Length) {
return null;
}
//Find the bin in which we live.
ObjectHolder temp = m_objects[index];
//Walk the chain in that bin. Return the ObjectHolder if we find it, otherwise
//return null.
while (temp!=null) {
if (temp.m_id==objectID) {
return temp;
}
temp = temp.m_next;
}
return temp;
}
internal ObjectHolder FindOrCreateObjectHolder(long objectID) {
ObjectHolder holder;
holder = FindObjectHolder(objectID);
if (holder==null) {
holder = new ObjectHolder(objectID);
AddObjectHolder(holder);
}
return holder;
}
/*===============================AddObjectHolder================================
**Action: Add the provided ObjectHolder to collection of ObjectHolders.
** Enlarges the collection as appropriate.
**Returns: void
**Arguments: holder The ObjectHolder to be added.
**Exceptions: Internal only. Caller should verify that holder is
** not null.
==============================================================================*/
private void AddObjectHolder(ObjectHolder holder) {
BCLDebug.Assert(holder!=null,"holder!=null");
BCLDebug.Trace("SER", "[AddObjectHolder]Adding ObjectHolder with id: ", holder.m_id, " Current Bins: ", m_objects.Length);
BCLDebug.Assert(holder.m_id>=0,"holder.m_id>=0");
//If the id that we need to place is greater than our current length, and less
//than the maximum allowable size of the array. We need to double the size
//of the array. If the array has already reached it's maximum allowable size,
//we chain elements off of the buckets.
if (holder.m_id>=m_objects.Length && m_objects.Length != MaxArraySize) {
int newSize=MaxArraySize;
if (holder.m_id<(MaxArraySize/2)) {
newSize = (m_objects.Length * 2);
//Keep doubling until we're larger than our target size.
//We could also do this with log operations, but that would
//be slower than the brute force approach.
while (newSize<=holder.m_id && newSizeMaxArraySize) {
newSize=MaxArraySize;
}
}
BCLDebug.Trace("SER", "[AddObjectHolder]Reallocating m_objects to have ", newSize, " bins");
ObjectHolder[] temp = new ObjectHolder[newSize];
Array.Copy(m_objects, temp, m_objects.Length);
m_objects = temp;
}
//Find the bin in which we live and make this new element the first element in the bin.
int index = (int)(holder.m_id & ArrayMask);
BCLDebug.Trace("SER", "[AddObjectHolder]Trying to put an object in bin ", index);
ObjectHolder tempHolder = m_objects[index];
holder.m_next = tempHolder;
m_objects[index] = holder;
}
private bool GetCompletionInfo(FixupHolder fixup, out ObjectHolder holder, out Object member, bool bThrowIfMissing) {
//Set the member id (String or MemberInfo) for the member being fixed up.
member = fixup.m_fixupInfo;
//Find the object required for the fixup. Throw if we can't find it.
holder = FindObjectHolder(fixup.m_id);
BCLDebug.Trace("SER", "[ObjectManager.GetCompletionInfo]Getting fixup info for: ", fixup.m_id);
// CompletelyFixed is our poorly named property which indicates if something requires a SerializationInfo fixup
// or is an incomplete object reference. We have this particular branch to handle valuetypes which implement
// ISerializable. In that case, we can't do any fixups on them later, so we need to delay the fixups further.
if (!holder.CompletelyFixed) {
if (holder.ObjectValue!=null && holder.ObjectValue is ValueType) {
BCLDebug.Trace("SER", "[ObjectManager.GetCompletionInfo]ValueType implementing ISerializable. Delaying fixup.");
SpecialFixupObjects.Add(holder);
return false;
}
}
if (holder==null || holder.CanObjectValueChange || holder.ObjectValue==null) {
if (bThrowIfMissing) {
BCLDebug.Trace("SER", "[GetCompletionInfo]Unable to find fixup for: ", fixup.m_id);
BCLDebug.Trace("SER", "[GetCompletionInfo]Holder: ", ((holder==null)?"":"Non Null"));
BCLDebug.Trace("SER", "[GetCompletionInfo]IsIncomplete: ", (holder.IsIncompleteObjectReference));
BCLDebug.Trace("SER", "[GetCompletionInfo]Object: ", ((holder.ObjectValue==null)?"":"Non Null"));
if (holder==null) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_NeverSeen"), fixup.m_id));
}
if (holder.IsIncompleteObjectReference) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_IORIncomplete"), fixup.m_id));
}
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ObjectNotSupplied"), fixup.m_id));
}
return false;
}
return true;
}
private void FixupSpecialObject(ObjectHolder holder) {
ISurrogateSelector uselessSelector=null;
BCLDebug.Assert(holder.RequiresSerInfoFixup,"[ObjectManager.FixupSpecialObject]holder.HasSurrogate||holder.HasISerializable");
if (holder.HasSurrogate) {
ISerializationSurrogate surrogate = holder.Surrogate;
BCLDebug.Assert(surrogate!=null,"surrogate!=null");
object returnValue = surrogate.SetObjectData(holder.ObjectValue, holder.SerializationInfo, m_context, uselessSelector);
if (returnValue != null)
{
if (!holder.CanSurrogatedObjectValueChange && returnValue != holder.ObjectValue)
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_NotCyclicallyReferenceableSurrogate"), surrogate.GetType().FullName));
holder.SetObjectValue(returnValue, this);
}
holder.m_surrogate = null;
holder.SetFlags();
} else {
//Set the object data
BCLDebug.Assert(holder.ObjectValue is ISerializable,"holder.m_object is ISerializable");
BCLDebug.Trace("SER","[ObjectManager.FixupSpecialObject]Fixing up ISerializable object ",holder.ObjectValue," with id ",holder.m_id);
CompleteISerializableObject(holder.ObjectValue, holder.SerializationInfo, m_context);
}
//Clear anything that we know that we're not going to need.
holder.SerializationInfo=null;
holder.RequiresSerInfoFixup = false;
// For value types, fixups would have been done. So the newly fixed object must be copied
// to its container.
if (holder.RequiresValueTypeFixup && holder.ValueTypeFixupPerformed){
DoValueTypeFixup(null, holder, holder.ObjectValue);
}
DoNewlyRegisteredObjectFixups(holder);
}
/*============================ResolveObjectReference============================
**Action:Unfortunately, an ObjectReference could actually be a reference to another
** object reference and we don't know how far we have to tunnel until we can find the real object. While
** we're still getting instances of IObjectReference back and we're still getting new objects, keep calling
** GetRealObject. Once we've got the new object, take care of all of the fixups
** that we can do now that we've got it.
==============================================================================*/
private bool ResolveObjectReference(ObjectHolder holder) {
Object tempObject;
BCLDebug.Assert(holder.IsIncompleteObjectReference,"holder.IsIncompleteObjectReference");
//In the pathological case, an Object implementing IObjectReference could return a reference
//to a different object which implements IObjectReference. This makes us vulnerable to a
//denial of service attack and stack overflow. If the depthCount becomes greater than
//MaxReferenceDepth, we'll throw a SerializationException.
int depthCount = 0;
//We wrap this in a try/catch block to handle the case where we're trying to resolve a chained
//list of object reference (e.g. an IObjectReference can't resolve itself without some information
//that's currently missing from the graph). We'll catch the NullReferenceException and come back
//and try again later. The downside of this scheme is that if the object actually needed to throw
//a NullReferenceException, it's being caught and turned into a SerializationException with a
//fairly cryptic message.
try {
do {
tempObject = holder.ObjectValue;
BCLDebug.Trace("SER", "[ResolveObjectReference]ID: ", holder.m_id);
BCLDebug.Trace("SER", "[ResolveObjectReference]HasISerializable: ", holder.HasISerializable);
holder.SetObjectValue(((IObjectReference)(holder.ObjectValue)).GetRealObject(m_context), this);
//The object didn't yet have enough information to resolve the reference, so we'll
//return false and the graph walker should call us back again after more objects have
//been resolved.
//<
if (holder.ObjectValue==null) {
holder.SetObjectValue(tempObject, this);
BCLDebug.Trace("SER", "Object: ", holder.m_id, " did NOT have enough information to resolve the IObjectReference.");
return false;
}
if (depthCount++==MaxReferenceDepth) {
throw new SerializationException(Environment.GetResourceString("Serialization_TooManyReferences"));
}
} while ((holder.ObjectValue is IObjectReference) && (tempObject!=holder.ObjectValue));
} catch (NullReferenceException) {
BCLDebug.Trace("SER", "[ResolveObjectReference]Caught exception trying to call GetRealObject.");
return false;
}
BCLDebug.Trace("SER", "Object: ", holder.m_id, " resolved the IObjectReference.");
holder.IsIncompleteObjectReference=false;
DoNewlyRegisteredObjectFixups(holder);
return true;
}
/*===============================DoValueTypeFixup===============================
**Action:
**Returns:
**Arguments:
** memberToFix -- the member in the object contained in holder being fixed up.
** holder -- the ObjectHolder for the object (a value type in this case) being completed.
** value -- the data to set into the field.
**Exceptions:
==============================================================================*/
private bool DoValueTypeFixup(FieldInfo memberToFix, ObjectHolder holder, Object value) {
TypedReference typedRef;
FieldInfo[] fieldsTemp=new FieldInfo[4];
FieldInfo[] fields=null;
int currentFieldIndex=0;
int[] arrayIndex = null;
ValueTypeFixupInfo currFixup=null;
Object fixupObj=holder.ObjectValue;
ObjectHolder originalHolder = holder;
BCLDebug.Assert(holder!=null, "[TypedReferenceBuilder.ctor]holder!=null");
BCLDebug.Assert(holder.RequiresValueTypeFixup, "[TypedReferenceBuilder.ctor]holder.RequiresValueTypeFixup");
//In order to get a TypedReference, we need to get a list of all of the FieldInfos to
//create the path from our outermost containing object down to the actual field which
//we'd like to set. This loop is used to build up that list.
while (holder.RequiresValueTypeFixup) {
BCLDebug.Trace("SER", "[DoValueTypeFixup] valueType fixsite = ", holder.ObjectValue, " fixobj=",value);
//Enlarge the array if required (this is actually fairly unlikely as it would require that we
//be nested more than 4 deep.
if ((currentFieldIndex + 1)>=fieldsTemp.Length) {
FieldInfo[] temp = new FieldInfo[fieldsTemp.Length * 2];
Array.Copy(fieldsTemp, temp, fieldsTemp.Length);
fieldsTemp = temp;
}
//Get the fixup information. If we have data for our parent field, add it to our list
//and continue the walk up to find the next outermost containing object. We cache the
//object that we have. In most cases, we could have just grabbed it after this loop finished.
//However, if the outermost containing object is an array, we need the object one further
//down the chain, so we have to do a lot of caching.
currFixup = holder.ValueFixup;
fixupObj = holder.ObjectValue; //Save the most derived
if (currFixup.ParentField!=null) {
FieldInfo parentField = currFixup.ParentField;
ObjectHolder tempHolder = FindObjectHolder(currFixup.ContainerID);
if (tempHolder.ObjectValue == null) {
break;
}
if (Nullable.GetUnderlyingType(parentField.FieldType) != null)
{
fieldsTemp[currentFieldIndex] = parentField.FieldType.GetField("value", BindingFlags.NonPublic|BindingFlags.Instance);
currentFieldIndex++;
}
fieldsTemp[currentFieldIndex] = parentField;
holder = tempHolder;
currentFieldIndex++;
} else {
//If we find an index into an array, save that information.
BCLDebug.Assert(currFixup.ParentIndex!=null, "[ObjectManager.DoValueTypeFixup]currFixup.ParentIndex!=null");
holder = FindObjectHolder(currFixup.ContainerID); //find the array to fix.
arrayIndex = currFixup.ParentIndex;
if (holder.ObjectValue==null) {
break;
}
break;
}
}
//If the outermost container isn't an array, we need to grab it. Otherwise, we just need to hang onto
//the boxed object that we already grabbed. We'll assign the boxed object back into the array as the
//last step.
if (!(holder.ObjectValue is Array) && holder.ObjectValue!=null) {
fixupObj = holder.ObjectValue;
BCLDebug.Assert(fixupObj!=null, "[ObjectManager.DoValueTypeFixup]FixupObj!=null");
}
#if false
//We thought that the valuetype had already been placed into it's parent, but when we started
//walking the track, we discovered a null, so that's clearly impossible. At this point, revert
//to just poking it into the most boxed version that we can.
if (fixupObj==null) {
fixupObj = originalHolder.ObjectValue;
FormatterServices.SerializationSetValue(memberToFix, fixupObj, value);
return true;
}
#endif
if (currentFieldIndex!=0) {
//MakeTypedReference requires an array of exactly the correct size that goes from the outermost object
//in to the innermost field. We currently have an array of arbitrary size that goes from the innermost
//object outwards. We create an array of the right size and do the copy.
fields = new FieldInfo[currentFieldIndex];
for (int i=0; i0,"temp.m_missingElementsRemaining>0");
temp.DecrementFixupsRemaining(this);
if (((temp.DirectlyDependentObjects))==0) {
BCLDebug.Trace("SER", "[DoNewlyRegisteredObjectFixups]Doing fixup for object ", temp.m_id);
BCLDebug.Trace("SER", "[DoNewlyRegisteredObjectFixups]ObjectValue ", ((temp.ObjectValue==null)?"":temp.ObjectValue));
// If this is null, we have the case where a fixup was registered for a child, the object
// required by the fixup was provided, and the object to be fixed hasn't yet been seen.
if (temp.ObjectValue!=null) {
CompleteObject(temp, true);
} else {
temp.MarkForCompletionWhenAvailable();
}
}
}
BCLDebug.Trace("SER", "[ObjectManager.DoNewlyRegisteredObjectFixups]Exiting.");
}
public virtual Object GetObject(long objectID) {
if (objectID<=0) {
throw new ArgumentOutOfRangeException("objectID", Environment.GetResourceString("ArgumentOutOfRange_ObjectID"));
}
//Find the bin in which we're interested. IObjectReference's shouldn't be returned -- the graph
//needs to link to the objects to which they refer, not to the references themselves.
ObjectHolder holder = FindObjectHolder(objectID);
BCLDebug.Trace("SER", "GetObject. objectID: ", objectID);
if (holder==null || holder.CanObjectValueChange) {
BCLDebug.Trace("SER", "GetObject. holder: null or IncompleteObjectReference");
return null;
}
BCLDebug.Trace("SER", "GetObject. holder contains: ", ((holder.ObjectValue==null)?"":holder.ObjectValue));
return holder.ObjectValue;
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public virtual void RegisterObject(Object obj, long objectID) {
RegisterObject(obj, objectID, null,0,null);
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public void RegisterObject(Object obj, long objectID, SerializationInfo info) {
RegisterObject(obj, objectID, info, 0, null);
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public void RegisterObject(Object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member) {
RegisterObject(obj, objectID, info, idOfContainingObj, member, null);
}
internal void RegisterString(String obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)
{
ObjectHolder temp;
BCLDebug.Assert(member == null || member is FieldInfo, "RegisterString - member is FieldInfo");
BCLDebug.Assert((FindObjectHolder(objectID) == null), "RegisterString - FindObjectHolder(objectID) == null");
temp = new ObjectHolder(obj, objectID, info, null, idOfContainingObj, (FieldInfo)member, null);
AddObjectHolder(temp);
return;
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public void RegisterObject(Object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex) {
ObjectHolder temp;
ISerializationSurrogate surrogate = null;
ISurrogateSelector useless;
if (obj==null) {
throw new ArgumentNullException("obj");
}
if (objectID<=0) {
throw new ArgumentOutOfRangeException("objectID", Environment.GetResourceString("ArgumentOutOfRange_ObjectID"));
}
if (member!=null && !(member is RuntimeFieldInfo) && !(member is SerializationFieldInfo)) {
throw new SerializationException(Environment.GetResourceString("Serialization_UnknownMemberInfo"));
}
if (m_selector != null)
{
Type selectorType=null;
if (CanCallGetType(obj)) {
selectorType = obj.GetType();
} else {
selectorType = typeof(MarshalByRefObject);
}
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]ID: ", objectID, "\tType: ", selectorType, "\tValue: ", obj);
//If we need a surrogate for this object, lets find it now.
surrogate = m_selector.GetSurrogate(selectorType, m_context, out useless);
}
//The object is interested in DeserializationEvents so lets register it.
if (obj is IDeserializationCallback) {
DeserializationEventHandler d = new DeserializationEventHandler(((IDeserializationCallback)obj).OnDeserialization);
AddOnDeserialization(d);
}
//Formatter developers may cache and reuse arrayIndex in their code.
//So that we don't get bitten by this, take a copy up front.
if (arrayIndex!=null) {
arrayIndex = (int[])arrayIndex.Clone();
}
temp = FindObjectHolder(objectID);
//This is the first time which we've seen the object, we need to create a new holder.
if (temp==null) {
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Adding a new object holder for ", objectID, "\tValueType: ", obj.GetType());
temp = new ObjectHolder(obj, objectID, info, surrogate, idOfContainingObj, (FieldInfo)member, arrayIndex);
AddObjectHolder(temp);
if (temp.RequiresDelayedFixup) {
SpecialFixupObjects.Add(temp);
}
// We cannot compute whether this has any fixups required or not
AddOnDeserialized(obj);
return;
}
//If the object isn't null, we've registered this before. Not good.
if (temp.ObjectValue!=null) {
throw new SerializationException(Environment.GetResourceString("Serialization_RegisterTwice"));
}
//Complete the data in the ObjectHolder
temp.UpdateData(obj, info, surrogate, idOfContainingObj, (FieldInfo)member, arrayIndex, this);
// The following case will only be true when somebody has registered a fixup on an object before
// registering the object itself. I don't believe that most well-behaved formatters will do this,
// but we need to allow it anyway. We will walk the list of fixups which have been recorded on
// the new object and fix those that we can. Because the user could still register later fixups
// on this object, we won't call any implementations of ISerializable now. If that's required,
// it will have to be handled by the code in DoFixups.
// README README: We have to do the UpdateData before
if (temp.DirectlyDependentObjects>0) {
CompleteObject(temp, false);
}
if (temp.RequiresDelayedFixup) {
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Tracking incomplete objref for element: ", temp.m_id);
SpecialFixupObjects.Add(temp);
}
if (temp.CompletelyFixed) {
//Here's where things get tricky. If this isn't an instance of IObjectReference, we need to walk it's fixup
//chain and decrement the counters on anything that has reached 0. Once we've notified all of the dependencies,
//we can simply clear the list of dependent objects.
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Calling DoNewlyRegisteredObjectFixups for element: ", temp.m_id);
DoNewlyRegisteredObjectFixups(temp);
temp.DependentObjects=null;
}
//Register the OnDeserialized methods to be invoked after deserialization is complete
if (temp.TotalDependentObjects > 0){
AddOnDeserialized(obj);
}
else {
RaiseOnDeserializedEvent(obj);
}
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Exiting.");
}
/*=========================CompleteISerializableObject==========================
**Action: Completes an object implementing ISerializable. This will involve calling that
** objects constructor which takes an instance of ISerializable and a StreamingContext.
**Returns: void.
**Arguments: Obj -- The object to be completed.
** info -- The SerializationInfo containing all info for obj.
** context -- The streaming context in which the serialization is taking place.
**Exceptions: ArgumentNullException if obj is null
** ArgumentException if obj does not implement ISerializable.
==============================================================================*/
internal void CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context) {
RuntimeConstructorInfo constInfo = null;
if (obj==null) {
throw new ArgumentNullException("obj");
}
if (!(obj is ISerializable)) {
throw new ArgumentException(Environment.GetResourceString("Serialization_NotISer"));
}
Type t = obj.GetType();
try {
#if !FEATURE_PAL
if (t == TypeOfWindowsIdentity && m_isCrossAppDomain)
constInfo = GetConstructor(t, SIWindowsIdentityConstructorTypes);
else
#endif
constInfo = GetConstructor(t);
} catch (Exception e) {
BCLDebug.Trace("SER", "[CompleteISerializableObject]Unable to get constructor for: ", t);
BCLDebug.Trace("SER", "[CompleteISerializableObject]Stack trace was: ", e);
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ConstructorNotFound"), t), e);
}
constInfo.SerializationInvoke(obj, info, context);
}
/*================================GetConstructor================================
**Action:
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
internal static RuntimeConstructorInfo GetConstructor(Type t) {
return GetConstructor(t, SIConstructorTypes);
}
internal static RuntimeConstructorInfo GetConstructor(Type t, Type[] ctorParams) {
BCLDebug.Assert(t!=null, "[GetConstructor]t!=null");
BCLDebug.Assert(t is RuntimeType, "[GetConstructor]t is RuntimeType");
RuntimeConstructorInfo ci;
if ((ci=(RuntimeConstructorInfo)t.Cache[CacheObjType.ConstructorInfo])==null) {
RuntimeType rt = (RuntimeType)t;
ci = rt.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, CallingConventions.Any, ctorParams, null) as RuntimeConstructorInfo;
if (ci==null) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ConstructorNotFound"), t.FullName));
}
t.Cache[CacheObjType.ConstructorInfo] = ci;
}
return ci;
}
public virtual void DoFixups() {
ObjectHolder temp;
int fixupCount=-1;
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Entering");
//The first thing that we need to do is fixup all of the objects which implement
//IObjectReference. This is complicated by the fact that we need to deal with IReferenceObjects
//objects that have a reference to an object implementing IObjectReference. We continually
//walk over the list of objects until we've completed all of the object references or until
//we can't resolve any more (which may happen if we have two objects implementing IObjectReference
//which have a circular dependency on each other). We don't explicitly catch the later case here,
//it will be caught when we try to do the rest of the fixups and discover that we have some that
//can't be completed.
while (fixupCount!=0) {
fixupCount=0;
//Walk all of the IObjectReferences and ensure that they've been properly completed.
ObjectHolderListEnumerator fixupObjectsEnum = SpecialFixupObjects.GetFixupEnumerator();
while (fixupObjectsEnum.MoveNext()) {
temp = fixupObjectsEnum.Current;
if (temp.ObjectValue == null) {
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Object with id: ", temp.m_id, " not found.");
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ObjectNotSupplied"), temp.m_id));
}
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Looking at object with id: ", temp.m_id, " which has ",
temp.TotalDependentObjects, " Total Dependent Fixups, but only ",
(temp.DependentObjects==null)?0:temp.DependentObjects.Count,
" directly dependent objects. Has it been fixed? ", temp.CompletelyFixed);
if (temp.TotalDependentObjects==0) {
if (temp.RequiresSerInfoFixup) {
FixupSpecialObject(temp);
fixupCount++;
} else if (!temp.IsIncompleteObjectReference) {
CompleteObject(temp, true);
}
if (temp.IsIncompleteObjectReference && ResolveObjectReference(temp)) {
fixupCount++;
}
}
}
}
BCLDebug.Assert(m_fixupCount>=0,"[ObjectManager.DoFixups]m_fixupCount>=0");
//If our count is 0, we're done and should just return
if (m_fixupCount==0) {
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]All fixups completed. We don't need to walk the list.");
if (TopObject is TypeLoadExceptionHolder)
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_TypeLoadFailure"), ((TypeLoadExceptionHolder)TopObject).TypeName));
return;
}
//If our count isn't 0, we had at least one case where an object referenced another object twice.
//Walk the entire list until the count is 0 or until we find an object which we can't complete.
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Remaining object length is: ", m_objects.Length);
for (int i=0; i0 /*|| temp.m_missingElements!=null*/) {
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Doing a delayed fixup on object ", temp.m_id);
CompleteObject(temp, true);
}
temp = temp.m_next;
}
if (m_fixupCount==0) {
return;
}
}
// this assert can be trigered by user code that manages fixups manually
BCLDebug.Correctness(false, "[ObjectManager.DoFixups] Fixup counting is incorrect.");
throw new SerializationException(Environment.GetResourceString("Serialization_IncorrectNumberOfFixups"));
}
/*================================RegisterFixup=================================
**Action: Do the actual grunt work of recording a fixup and registering the dependency.
** Create the necessary ObjectHolders and use them to do the addition.
**Returns: void
**Arguments: fixup -- The FixupHolder to be added.
** objectToBeFixed -- The id of the object requiring the fixup.
** objectRequired -- The id of the object required to do the fixup.
**Exceptions: None. This is internal-only, so all checking should have been done by this time.
==============================================================================*/
private void RegisterFixup(FixupHolder fixup, long objectToBeFixed, long objectRequired) {
//Record the fixup with the object that needs it.
ObjectHolder ohToBeFixed = FindOrCreateObjectHolder(objectToBeFixed);
ObjectHolder ohRequired;
if (ohToBeFixed.RequiresSerInfoFixup && fixup.m_fixupType == FixupHolder.MemberFixup) {
throw new SerializationException(Environment.GetResourceString("Serialization_InvalidFixupType"));
}
//Add the fixup to the list.
ohToBeFixed.AddFixup(fixup, this);
//Find the object on which we're dependent and note the dependency.
//These dependencies will be processed when the object is supplied.
ohRequired = FindOrCreateObjectHolder(objectRequired);
ohRequired.AddDependency(objectToBeFixed);
m_fixupCount++;
}
public virtual void RecordFixup(long objectToBeFixed, MemberInfo member, long objectRequired) {
//Verify our arguments
if (objectToBeFixed<=0 || objectRequired<=0) {
throw new ArgumentOutOfRangeException(((objectToBeFixed<=0)?"objectToBeFixed":"objectRequired"),
Environment.GetResourceString("Serialization_IdTooSmall"));
}
if (member==null) {
throw new ArgumentNullException("member");
}
if (!(member is RuntimeFieldInfo) && !(member is SerializationFieldInfo)) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_InvalidType"), member.GetType().ToString()));
}
BCLDebug.Trace("SER", "RecordFixup. ObjectToBeFixed: ", objectToBeFixed, "\tMember: ", member.Name, "\tRequiredObject: ", objectRequired);
//Create a new fixup holder
FixupHolder fixup = new FixupHolder(objectRequired, member, FixupHolder.MemberFixup);
RegisterFixup(fixup, objectToBeFixed, objectRequired);
}
/*==============================RecordDelayedFixup==============================
**Action:
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
public virtual void RecordDelayedFixup(long objectToBeFixed, String memberName, long objectRequired) {
//Verify our arguments
if (objectToBeFixed<=0 || objectRequired<=0) {
throw new ArgumentOutOfRangeException(((objectToBeFixed<=0)?"objectToBeFixed":"objectRequired"),
Environment.GetResourceString("Serialization_IdTooSmall"));
}
if (memberName==null) {
throw new ArgumentNullException("memberName");
}
BCLDebug.Trace("SER", "RecordDelayedFixup. ObjectToBeFixed: ", objectToBeFixed, "\tMember: ", memberName, "\tRequiredObject: ", objectRequired);
//Create a new fixup holder
FixupHolder fixup = new FixupHolder(objectRequired, memberName, FixupHolder.DelayedFixup);
RegisterFixup(fixup, objectToBeFixed, objectRequired);
}
/*===========================RecordArrayElementFixup============================
**Action:
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
public virtual void RecordArrayElementFixup(long arrayToBeFixed, int index, long objectRequired) {
int[] indexArray = new int[1];
indexArray[0]=index;
BCLDebug.Trace("SER", "RecordArrayElementFixup. ObjectToBeFixed: ", arrayToBeFixed, "\tIndex: ", index, "\tRequiredObject: ", objectRequired);
RecordArrayElementFixup(arrayToBeFixed, indexArray, objectRequired);
}
public virtual void RecordArrayElementFixup(long arrayToBeFixed, int[] indices, long objectRequired) {
//Verify our arguments
if (arrayToBeFixed<=0 || objectRequired<=0) {
throw new ArgumentOutOfRangeException(((arrayToBeFixed<=0)?"objectToBeFixed":"objectRequired"),
Environment.GetResourceString("Serialization_IdTooSmall"));
}
if (indices==null) {
throw new ArgumentNullException("indices");
}
BCLDebug.Trace("SER", "RecordArrayElementFixup. ArrayToBeFixed: ", arrayToBeFixed, "\tRequiredObject: ", objectRequired);
FixupHolder fixup = new FixupHolder(objectRequired, indices, FixupHolder.ArrayFixup);
RegisterFixup(fixup, arrayToBeFixed, objectRequired);
}
/*==========================RaiseDeserializationEvent===========================
**Action:Raises the deserialization event to any registered object which implements
** IDeserializationCallback.
**Returns: void
**Arguments: none
**Exceptions: None
==============================================================================*/
public virtual void RaiseDeserializationEvent() {
// Invoke OnDerserialized event if applicable
if (m_onDeserializedHandler != null) {
m_onDeserializedHandler(m_context);
}
if (m_onDeserializationHandler!=null) {
m_onDeserializationHandler(null);
}
}
internal virtual void AddOnDeserialization(DeserializationEventHandler handler) {
m_onDeserializationHandler = (DeserializationEventHandler)Delegate.Combine(m_onDeserializationHandler, handler);
}
internal virtual void RemoveOnDeserialization(DeserializationEventHandler handler) {
m_onDeserializationHandler = (DeserializationEventHandler)Delegate.Remove(m_onDeserializationHandler, handler);
}
internal virtual void AddOnDeserialized(Object obj)
{
SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType());
m_onDeserializedHandler = cache.AddOnDeserialized(obj, m_onDeserializedHandler);
}
internal virtual void RaiseOnDeserializedEvent(Object obj)
{
SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType());
cache.InvokeOnDeserialized(obj, m_context);
}
public void RaiseOnDeserializingEvent(Object obj)
{
// Run the OnDeserializing methods
SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType());
cache.InvokeOnDeserializing(obj, m_context);
}
}
internal sealed class ObjectHolder {
internal const int INCOMPLETE_OBJECT_REFERENCE = 0x0001;
internal const int HAS_ISERIALIZABLE = 0x0002;
internal const int HAS_SURROGATE = 0x0004;
internal const int REQUIRES_VALUETYPE_FIXUP = 0x0008;
internal const int REQUIRES_DELAYED_FIXUP = HAS_ISERIALIZABLE | HAS_SURROGATE | INCOMPLETE_OBJECT_REFERENCE;
internal const int SER_INFO_FIXED = 0x4000;
internal const int VALUETYPE_FIXUP_PERFORMED = 0x8000;
private Object m_object;
internal long m_id;
private int m_missingElementsRemaining;
private int m_missingDecendents;
internal SerializationInfo m_serInfo;
internal ISerializationSurrogate m_surrogate;
internal FixupHolderList m_missingElements;
internal LongList m_dependentObjects;
internal ObjectHolder m_next;
internal int m_flags;
private bool m_markForFixupWhenAvailable;
private ValueTypeFixupInfo m_valueFixup;
private TypeLoadExceptionHolder m_typeLoad = null;
private bool m_reachable = false;
internal ObjectHolder(long objID)
: this(null, objID, null, null, 0, null, null) {
}
internal ObjectHolder(Object obj, long objID, SerializationInfo info,
ISerializationSurrogate surrogate, long idOfContainingObj, FieldInfo field, int[] arrayIndex) {
BCLDebug.Assert(objID>=0,"objID>=0");
m_object=obj; //May be null;
m_id=objID;
m_flags=0;
m_missingElementsRemaining=0;
m_missingDecendents = 0;
m_dependentObjects=null;
m_next=null;
m_serInfo = info;
m_surrogate = surrogate;
m_markForFixupWhenAvailable = false;
if (obj is TypeLoadExceptionHolder)
{
m_typeLoad = (TypeLoadExceptionHolder)obj;
}
if (idOfContainingObj!=0 && ((field!=null && field.FieldType.IsValueType) || arrayIndex!=null)) {
if (idOfContainingObj == objID) {
throw new SerializationException(Environment.GetResourceString("Serialization_ParentChildIdentical"));
}
m_valueFixup = new ValueTypeFixupInfo(idOfContainingObj, field, arrayIndex);
}
SetFlags();
}
internal ObjectHolder(String obj, long objID, SerializationInfo info,
ISerializationSurrogate surrogate, long idOfContainingObj, FieldInfo field, int[] arrayIndex) {
BCLDebug.Assert(objID>=0,"objID>=0");
m_object=obj; //May be null;
m_id=objID;
m_flags=0;
m_missingElementsRemaining=0;
m_missingDecendents = 0;
m_dependentObjects=null;
m_next=null;
m_serInfo = info;
m_surrogate = surrogate;
m_markForFixupWhenAvailable = false;
if (idOfContainingObj!=0 && arrayIndex!=null) {
m_valueFixup = new ValueTypeFixupInfo(idOfContainingObj, field, arrayIndex);
}
if (m_valueFixup!=null) {
m_flags|=REQUIRES_VALUETYPE_FIXUP;
}
}
private void IncrementDescendentFixups(int amount) {
m_missingDecendents+=amount;
}
internal void DecrementFixupsRemaining(ObjectManager manager) {
m_missingElementsRemaining--;
if (RequiresValueTypeFixup) {
UpdateDescendentDependencyChain(-1, manager);
}
}
/*===============================RemoveDependency===============================
**Action: Removes a dependency of the object represented in this holder.
** This is normally the result of the dependency having been filled when
** the object is going to be only partially completed. If we plan to fully
** update the object, we do not take the work to do this.
**Returns: void.
**Arguments: id -- The id of the object for which to remove the dependency.
**Exceptions: None, error handling through asserts.
==============================================================================*/
internal void RemoveDependency(long id) {
BCLDebug.Assert(m_dependentObjects!=null, "[ObjectHolder.RemoveDependency]m_dependentObjects!=null");
BCLDebug.Assert(id>=0, "[ObjectHolder.RemoveDependency]id>=0");
m_dependentObjects.RemoveElement(id);
}
/*===================================AddFixup===================================
**Action: Note a fixup that has to be done before this object can be completed.
** Fixups are things that need to happen when other objects in the graph
** are added. Dependencies are things that need to happen when this object
** is added.
**Returns: void
**Arguments: fixup -- The fixup holder containing enough information to complete the fixup.
**Exceptions: None.
==============================================================================*/
internal void AddFixup(FixupHolder fixup, ObjectManager manager) {
if (m_missingElements==null) {
m_missingElements = new FixupHolderList();
}
m_missingElements.Add(fixup);
m_missingElementsRemaining++;
if (RequiresValueTypeFixup) {
UpdateDescendentDependencyChain(1, manager);
}
}
/*==========================UpdateTotalDependencyChain==========================
**Action: Updates the total list of dependencies to account for a fixup being added
** or completed in a child value class. This will update all value classes
** containing that child and the object which contains all of them.
**Returns: void
**Arguments: amount -- the amount by which to increment (or decrement) the dependency chain.
** manager -- The ObjectManager used to lookup other objects up the chain.
**Exceptions: None. Asserts only.
==============================================================================*/
private void UpdateDescendentDependencyChain(int amount, ObjectManager manager) {
ObjectHolder holder = this;
//This loop walks one more object up the chain than there are valuetypes. This
//is because we need to increment the TotalFixups in the holders as well.
do {
holder = manager.FindOrCreateObjectHolder(holder.ContainerID);
BCLDebug.Trace("SER", "[ObjectManager.UpdateDescendentDependencyChain]Looking for holder with id: ", holder.ContainerID);
BCLDebug.Assert(holder!=null, "[ObjectHolder.UpdateTotalDependencyChain]holder!=null");
holder.IncrementDescendentFixups(amount);
} while (holder.RequiresValueTypeFixup);
}
/*================================AddDependency=================================
**Action: Note an object which is dependent on the one which will be contained in
** this ObjectHolder. Dependencies should only be added if the object hasn't
** yet been added. NB: An incomplete object counts as having no object.
**Returns: void
**Arguments: dependentObject -- the id of the object which is dependent on this object being provided.
**Exceptions: None.
==============================================================================*/
internal void AddDependency(long dependentObject) {
if (m_dependentObjects==null) {
m_dependentObjects = new LongList();
}
m_dependentObjects.Add(dependentObject);
}
/*==================================UpdateData==================================
**Action: Update the data in the object holder. This should be called when the object
** is finally registered. Presumably the ObjectHolder was created to track
** some dependencies or preregistered fixups and we now need to actually record the
** object and other associated data. We take this opportunity to set the flags
** so that we can do some faster processing in the future.
**Returns: void
**Arguments: obj -- The object being held by this object holder. (This should no longer be null).
** info --The SerializationInfo associated with this object, only required if we're doing delayed fixups.
** surrogate -- The surrogate handling this object. May be null.
** idOfContainer -- The id of the object containing this one if this is a valuetype.
** member -- the MemberInfo of this object's position in it's container if this is a valuetype.
** manager -- the ObjectManager being used to track these ObjectHolders.
**Exceptions: None. Asserts only.
==============================================================================*/
internal void UpdateData(Object obj, SerializationInfo info, ISerializationSurrogate surrogate, long idOfContainer, FieldInfo field, int[] arrayIndex, ObjectManager manager) {
BCLDebug.Assert(obj!=null,"obj!=null");
BCLDebug.Assert(m_id>0,"m_id>0");
//Record the fields that we can.
SetObjectValue(obj, manager);
m_serInfo = info;
m_surrogate = surrogate;
if (idOfContainer!=0 && ((field!=null && field.FieldType.IsValueType) || arrayIndex!=null)) {
if (idOfContainer == m_id) {
throw new SerializationException(Environment.GetResourceString("Serialization_ParentChildIdentical"));
}
m_valueFixup = new ValueTypeFixupInfo(idOfContainer, field, arrayIndex);
}
SetFlags();
if (RequiresValueTypeFixup) {
UpdateDescendentDependencyChain(m_missingElementsRemaining, manager);
}
}
internal void MarkForCompletionWhenAvailable() {
m_markForFixupWhenAvailable = true;
}
/*===================================SetFlags===================================
**Action: An internal-only routine to set the flags based upon the data contained in
** the ObjectHolder
**Returns: Void
**Arguments: None
**Exceptions: None
==============================================================================*/
internal void SetFlags() {
if (m_object is IObjectReference) {
m_flags|=INCOMPLETE_OBJECT_REFERENCE;
}
m_flags &= ~(HAS_ISERIALIZABLE | HAS_SURROGATE);
if (m_surrogate!=null)
m_flags|=HAS_SURROGATE;
else if (m_object is ISerializable)
m_flags|=HAS_ISERIALIZABLE;
if (m_valueFixup!=null) {
m_flags|=REQUIRES_VALUETYPE_FIXUP;
}
}
internal bool IsIncompleteObjectReference {
get { return (m_flags & (INCOMPLETE_OBJECT_REFERENCE /*| HAS_SURROGATE*/)) != 0; }
set {
if (value) {
m_flags|=INCOMPLETE_OBJECT_REFERENCE;
} else {
m_flags&=~INCOMPLETE_OBJECT_REFERENCE;
}
}
}
internal bool RequiresDelayedFixup {
get { return (m_flags & REQUIRES_DELAYED_FIXUP)!=0; }
}
internal bool RequiresValueTypeFixup {
get { return (m_flags & REQUIRES_VALUETYPE_FIXUP)!=0; }
}
// ValueTypes which require fixups are initially handed to the ObjectManager
// as boxed objects. When they're still boxed objects, we should just do fixups
// on them like we would any other object. As soon as they're pushed into their
// containing object we set ValueTypeFixupPerformed to true and have to go through
// a more complicated path to set fixed up valuetype objects.
// We check whether or not there are any dependent objects.
internal bool ValueTypeFixupPerformed {
get {
BCLDebug.Trace("SER", "[ObjectManager.ValueTypeFixupPerformed]Flags: ", m_flags & VALUETYPE_FIXUP_PERFORMED);
BCLDebug.Trace("SER", "[ObjectManager.ValueTypeFixupPerformed]DependentObjects: ", (m_dependentObjects==null)?"":m_dependentObjects.Count.ToString());
return ( ((m_flags & VALUETYPE_FIXUP_PERFORMED)!=0)||
(m_object!=null && ((m_dependentObjects==null) || m_dependentObjects.Count==0))); }
set {
if (value) {
m_flags|=VALUETYPE_FIXUP_PERFORMED;
}
}
}
internal bool HasISerializable {
get {
return (m_flags & HAS_ISERIALIZABLE)!=0;
}
}
internal bool HasSurrogate {
get { return (m_flags & HAS_SURROGATE)!=0; }
}
internal bool CanSurrogatedObjectValueChange
{
get
{
return (m_surrogate == null || m_surrogate.GetType() != typeof(SurrogateForCyclicalReference));
}
}
internal bool CanObjectValueChange
{
get
{
if (IsIncompleteObjectReference)
return true;
if (HasSurrogate)
return CanSurrogatedObjectValueChange;
return false;
}
}
internal int DirectlyDependentObjects {
get {
return m_missingElementsRemaining;
}
}
internal int TotalDependentObjects {
get {
return m_missingElementsRemaining + m_missingDecendents;
}
}
internal bool Reachable {
get { return m_reachable; }
set { m_reachable = value; }
}
internal bool TypeLoadExceptionReachable {
get { return m_typeLoad != null; }
}
internal TypeLoadExceptionHolder TypeLoadException {
get { return m_typeLoad; }
set { m_typeLoad = value; }
}
internal Object ObjectValue {
get {
return m_object;
}
}
internal void SetObjectValue(Object obj, ObjectManager manager) {
m_object = obj;
if (obj == manager.TopObject)
m_reachable = true;
if (obj is TypeLoadExceptionHolder)
m_typeLoad = (TypeLoadExceptionHolder)obj;
if (m_markForFixupWhenAvailable) {
manager.CompleteObject(this, true);
}
}
internal SerializationInfo SerializationInfo {
get {
return m_serInfo;
}
set {
m_serInfo = value;
}
}
internal ISerializationSurrogate Surrogate {
get {
return m_surrogate;
}
}
internal LongList DependentObjects {
get {
return m_dependentObjects;
}
set {
m_dependentObjects = value;
}
}
internal bool RequiresSerInfoFixup {
get {
if (((m_flags & HAS_SURROGATE)==0) && ((m_flags & HAS_ISERIALIZABLE)==0)) {
return false;
}
return (m_flags & SER_INFO_FIXED)==0;
}
set {
if (!value) {
m_flags|=SER_INFO_FIXED;
} else {
m_flags&=~SER_INFO_FIXED;
}
}
}
internal ValueTypeFixupInfo ValueFixup {
get {
return m_valueFixup;
}
}
internal bool CompletelyFixed {
get {
return (!RequiresSerInfoFixup && !IsIncompleteObjectReference);
}
}
internal long ContainerID {
get {
if (m_valueFixup!=null) {
return m_valueFixup.ContainerID;
}
return 0;
}
}
}
[Serializable()]
internal class FixupHolder {
internal const int ArrayFixup=0x1;
internal const int MemberFixup=0x2;
internal const int DelayedFixup=0x4;
internal long m_id;
internal Object m_fixupInfo; //This is either an array index, a String, or a MemberInfo
internal int m_fixupType;
internal FixupHolder(long id, Object fixupInfo, int fixupType) {
BCLDebug.Assert(id>0,"id>0");
BCLDebug.Assert(fixupInfo!=null,"fixupInfo!=null");
BCLDebug.Assert(fixupType==ArrayFixup || fixupType == MemberFixup || fixupType==DelayedFixup,"fixupType==ArrayFixup || fixupType == MemberFixup || fixupType==DelayedFixup");
m_id = id;
m_fixupInfo = fixupInfo;
m_fixupType = fixupType;
}
}
[Serializable()]
internal class FixupHolderList {
internal const int InitialSize = 2;
internal FixupHolder[] m_values;
internal int m_count;
internal FixupHolderList() : this(InitialSize) {
}
internal FixupHolderList(int startingSize) {
m_count=0;
m_values = new FixupHolder[startingSize];
}
internal virtual void Add(long id, Object fixupInfo) {
if (m_count==m_values.Length) {
EnlargeArray();
}
m_values[m_count].m_id=id;
m_values[m_count++].m_fixupInfo = fixupInfo;
}
internal virtual void Add(FixupHolder fixup) {
if (m_count==m_values.Length) {
EnlargeArray();
}
m_values[m_count++]=fixup;
}
private void EnlargeArray() {
int newLength = m_values.Length*2;
if (newLength<0) {
if (newLength==Int32.MaxValue) {
throw new SerializationException(Environment.GetResourceString("Serialization_TooManyElements"));
}
newLength=Int32.MaxValue;
}
FixupHolder[] temp = new FixupHolder[newLength];
Array.Copy(m_values, temp, m_count);
m_values=temp;
}
}
[Serializable()]
internal class LongList {
private const int InitialSize = 2;
private long [] m_values;
private int m_count; //The total number of valid items still in the list;
private int m_totalItems; //The total number of allocated entries.
//This includes space for items which have been marked as deleted.
private int m_currentItem; //Used when doing an enumeration over the list.
//
// An m_currentItem of -1 indicates that the enumeration hasn't been started.
// An m_values[xx] of -1 indicates that the item has been deleted.
//
internal LongList() : this(InitialSize) {
}
internal LongList(int startingSize) {
m_count=0;
m_totalItems = 0;
m_values = new long[startingSize];
}
internal void Add(long value) {
if (m_totalItems==m_values.Length) {
EnlargeArray();
}
m_values[m_totalItems++]=value;
m_count++;
}
internal int Count {
get {
return m_count;
}
}
internal void StartEnumeration() {
m_currentItem = -1;
}
internal bool MoveNext() {
while (++m_currentItem < m_totalItems && m_values[m_currentItem]==-1) {
}
if (m_currentItem==m_totalItems) {
return false;
}
return true;
}
internal long Current {
get {
BCLDebug.Assert(m_currentItem!=-1, "[LongList.Current]m_currentItem!=-1");
BCLDebug.Assert(m_values[m_currentItem]!=-1, "[LongList.Current]m_values[m_currentItem]!=-1");
return m_values[m_currentItem];
}
}
internal bool RemoveElement(long value) {
int i;
for (i=0; i0 && startingSize<0x1000,"startingSize>0 && startingSize<0x1000");
m_count =0;
m_values = new ObjectHolder[startingSize];
}
internal virtual void Add(ObjectHolder value) {
if (m_count==m_values.Length) {
EnlargeArray();
}
m_values[m_count++]=value;
}
internal ObjectHolderListEnumerator GetFixupEnumerator() {
return new ObjectHolderListEnumerator(this, true);
}
private void EnlargeArray() {
BCLDebug.Trace("SER", "[ObjectHolderList.EnlargeArray]Enlarging array of size ", m_values.Length);
int newLength = m_values.Length*2;
if (newLength<0) {
if (newLength==Int32.MaxValue) {
throw new SerializationException(Environment.GetResourceString("Serialization_TooManyElements"));
}
newLength=Int32.MaxValue;
}
ObjectHolder[] temp = new ObjectHolder[newLength];
Array.Copy(m_values, temp, m_count);
m_values = temp;
}
internal int Version {
get {
return m_count;
}
}
internal int Count {
get {
return m_count;
}
}
}
internal class ObjectHolderListEnumerator {
bool m_isFixupEnumerator;
ObjectHolderList m_list;
int m_startingVersion;
int m_currPos;
internal ObjectHolderListEnumerator(ObjectHolderList list, bool isFixupEnumerator) {
BCLDebug.Assert(list!=null, "[ObjectHolderListEnumerator.ctor]list!=null");
m_list = list;
m_startingVersion = m_list.Version;
m_currPos=-1;
m_isFixupEnumerator = isFixupEnumerator;
}
internal bool MoveNext() {
BCLDebug.Assert(m_startingVersion==m_list.Version, "[ObjectHolderListEnumerator.MoveNext]m_startingVersion==m_list.Version");
if (m_isFixupEnumerator) {
while (++m_currPos < m_list.Count && m_list.m_values[m_currPos].CompletelyFixed) {
}
if (m_currPos==m_list.Count) {
return false;
}
return true;
} else {
m_currPos++;
if (m_currPos==m_list.Count) {
return false;
}
return true;
}
}
internal ObjectHolder Current {
get {
BCLDebug.Assert(m_currPos!=-1, "[ObjectHolderListEnumerator.Current]m_currPos!=-1");
BCLDebug.Assert(m_currPosobjectID.
**This function does no error checking, it assumes that all of that has been done already.
**Returns: The ObjectHolder for objectID or null if it doesn't exist.
**Arguments: objectID -- The objectID of the Object for which we're searching.
**Exceptions: None. This is internal only.
**Callers should verify that objectID is greater than 0.
==============================================================================*/
internal ObjectHolder FindObjectHolder(long objectID) {
BCLDebug.Assert(objectID>0,"objectID>0");
//The index of the bin in which we live is rightmost n bits of the objectID.
int index = (int)(objectID & ArrayMask);
if (index>=m_objects.Length) {
return null;
}
//Find the bin in which we live.
ObjectHolder temp = m_objects[index];
//Walk the chain in that bin. Return the ObjectHolder if we find it, otherwise
//return null.
while (temp!=null) {
if (temp.m_id==objectID) {
return temp;
}
temp = temp.m_next;
}
return temp;
}
internal ObjectHolder FindOrCreateObjectHolder(long objectID) {
ObjectHolder holder;
holder = FindObjectHolder(objectID);
if (holder==null) {
holder = new ObjectHolder(objectID);
AddObjectHolder(holder);
}
return holder;
}
/*===============================AddObjectHolder================================
**Action: Add the provided ObjectHolder to collection of ObjectHolders.
** Enlarges the collection as appropriate.
**Returns: void
**Arguments: holder The ObjectHolder to be added.
**Exceptions: Internal only. Caller should verify that holder is
** not null.
==============================================================================*/
private void AddObjectHolder(ObjectHolder holder) {
BCLDebug.Assert(holder!=null,"holder!=null");
BCLDebug.Trace("SER", "[AddObjectHolder]Adding ObjectHolder with id: ", holder.m_id, " Current Bins: ", m_objects.Length);
BCLDebug.Assert(holder.m_id>=0,"holder.m_id>=0");
//If the id that we need to place is greater than our current length, and less
//than the maximum allowable size of the array. We need to double the size
//of the array. If the array has already reached it's maximum allowable size,
//we chain elements off of the buckets.
if (holder.m_id>=m_objects.Length && m_objects.Length != MaxArraySize) {
int newSize=MaxArraySize;
if (holder.m_id<(MaxArraySize/2)) {
newSize = (m_objects.Length * 2);
//Keep doubling until we're larger than our target size.
//We could also do this with log operations, but that would
//be slower than the brute force approach.
while (newSize<=holder.m_id && newSizeMaxArraySize) {
newSize=MaxArraySize;
}
}
BCLDebug.Trace("SER", "[AddObjectHolder]Reallocating m_objects to have ", newSize, " bins");
ObjectHolder[] temp = new ObjectHolder[newSize];
Array.Copy(m_objects, temp, m_objects.Length);
m_objects = temp;
}
//Find the bin in which we live and make this new element the first element in the bin.
int index = (int)(holder.m_id & ArrayMask);
BCLDebug.Trace("SER", "[AddObjectHolder]Trying to put an object in bin ", index);
ObjectHolder tempHolder = m_objects[index];
holder.m_next = tempHolder;
m_objects[index] = holder;
}
private bool GetCompletionInfo(FixupHolder fixup, out ObjectHolder holder, out Object member, bool bThrowIfMissing) {
//Set the member id (String or MemberInfo) for the member being fixed up.
member = fixup.m_fixupInfo;
//Find the object required for the fixup. Throw if we can't find it.
holder = FindObjectHolder(fixup.m_id);
BCLDebug.Trace("SER", "[ObjectManager.GetCompletionInfo]Getting fixup info for: ", fixup.m_id);
// CompletelyFixed is our poorly named property which indicates if something requires a SerializationInfo fixup
// or is an incomplete object reference. We have this particular branch to handle valuetypes which implement
// ISerializable. In that case, we can't do any fixups on them later, so we need to delay the fixups further.
if (!holder.CompletelyFixed) {
if (holder.ObjectValue!=null && holder.ObjectValue is ValueType) {
BCLDebug.Trace("SER", "[ObjectManager.GetCompletionInfo]ValueType implementing ISerializable. Delaying fixup.");
SpecialFixupObjects.Add(holder);
return false;
}
}
if (holder==null || holder.CanObjectValueChange || holder.ObjectValue==null) {
if (bThrowIfMissing) {
BCLDebug.Trace("SER", "[GetCompletionInfo]Unable to find fixup for: ", fixup.m_id);
BCLDebug.Trace("SER", "[GetCompletionInfo]Holder: ", ((holder==null)?"":"Non Null"));
BCLDebug.Trace("SER", "[GetCompletionInfo]IsIncomplete: ", (holder.IsIncompleteObjectReference));
BCLDebug.Trace("SER", "[GetCompletionInfo]Object: ", ((holder.ObjectValue==null)?"":"Non Null"));
if (holder==null) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_NeverSeen"), fixup.m_id));
}
if (holder.IsIncompleteObjectReference) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_IORIncomplete"), fixup.m_id));
}
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ObjectNotSupplied"), fixup.m_id));
}
return false;
}
return true;
}
private void FixupSpecialObject(ObjectHolder holder) {
ISurrogateSelector uselessSelector=null;
BCLDebug.Assert(holder.RequiresSerInfoFixup,"[ObjectManager.FixupSpecialObject]holder.HasSurrogate||holder.HasISerializable");
if (holder.HasSurrogate) {
ISerializationSurrogate surrogate = holder.Surrogate;
BCLDebug.Assert(surrogate!=null,"surrogate!=null");
object returnValue = surrogate.SetObjectData(holder.ObjectValue, holder.SerializationInfo, m_context, uselessSelector);
if (returnValue != null)
{
if (!holder.CanSurrogatedObjectValueChange && returnValue != holder.ObjectValue)
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_NotCyclicallyReferenceableSurrogate"), surrogate.GetType().FullName));
holder.SetObjectValue(returnValue, this);
}
holder.m_surrogate = null;
holder.SetFlags();
} else {
//Set the object data
BCLDebug.Assert(holder.ObjectValue is ISerializable,"holder.m_object is ISerializable");
BCLDebug.Trace("SER","[ObjectManager.FixupSpecialObject]Fixing up ISerializable object ",holder.ObjectValue," with id ",holder.m_id);
CompleteISerializableObject(holder.ObjectValue, holder.SerializationInfo, m_context);
}
//Clear anything that we know that we're not going to need.
holder.SerializationInfo=null;
holder.RequiresSerInfoFixup = false;
// For value types, fixups would have been done. So the newly fixed object must be copied
// to its container.
if (holder.RequiresValueTypeFixup && holder.ValueTypeFixupPerformed){
DoValueTypeFixup(null, holder, holder.ObjectValue);
}
DoNewlyRegisteredObjectFixups(holder);
}
/*============================ResolveObjectReference============================
**Action:Unfortunately, an ObjectReference could actually be a reference to another
** object reference and we don't know how far we have to tunnel until we can find the real object. While
** we're still getting instances of IObjectReference back and we're still getting new objects, keep calling
** GetRealObject. Once we've got the new object, take care of all of the fixups
** that we can do now that we've got it.
==============================================================================*/
private bool ResolveObjectReference(ObjectHolder holder) {
Object tempObject;
BCLDebug.Assert(holder.IsIncompleteObjectReference,"holder.IsIncompleteObjectReference");
//In the pathological case, an Object implementing IObjectReference could return a reference
//to a different object which implements IObjectReference. This makes us vulnerable to a
//denial of service attack and stack overflow. If the depthCount becomes greater than
//MaxReferenceDepth, we'll throw a SerializationException.
int depthCount = 0;
//We wrap this in a try/catch block to handle the case where we're trying to resolve a chained
//list of object reference (e.g. an IObjectReference can't resolve itself without some information
//that's currently missing from the graph). We'll catch the NullReferenceException and come back
//and try again later. The downside of this scheme is that if the object actually needed to throw
//a NullReferenceException, it's being caught and turned into a SerializationException with a
//fairly cryptic message.
try {
do {
tempObject = holder.ObjectValue;
BCLDebug.Trace("SER", "[ResolveObjectReference]ID: ", holder.m_id);
BCLDebug.Trace("SER", "[ResolveObjectReference]HasISerializable: ", holder.HasISerializable);
holder.SetObjectValue(((IObjectReference)(holder.ObjectValue)).GetRealObject(m_context), this);
//The object didn't yet have enough information to resolve the reference, so we'll
//return false and the graph walker should call us back again after more objects have
//been resolved.
//<
if (holder.ObjectValue==null) {
holder.SetObjectValue(tempObject, this);
BCLDebug.Trace("SER", "Object: ", holder.m_id, " did NOT have enough information to resolve the IObjectReference.");
return false;
}
if (depthCount++==MaxReferenceDepth) {
throw new SerializationException(Environment.GetResourceString("Serialization_TooManyReferences"));
}
} while ((holder.ObjectValue is IObjectReference) && (tempObject!=holder.ObjectValue));
} catch (NullReferenceException) {
BCLDebug.Trace("SER", "[ResolveObjectReference]Caught exception trying to call GetRealObject.");
return false;
}
BCLDebug.Trace("SER", "Object: ", holder.m_id, " resolved the IObjectReference.");
holder.IsIncompleteObjectReference=false;
DoNewlyRegisteredObjectFixups(holder);
return true;
}
/*===============================DoValueTypeFixup===============================
**Action:
**Returns:
**Arguments:
** memberToFix -- the member in the object contained in holder being fixed up.
** holder -- the ObjectHolder for the object (a value type in this case) being completed.
** value -- the data to set into the field.
**Exceptions:
==============================================================================*/
private bool DoValueTypeFixup(FieldInfo memberToFix, ObjectHolder holder, Object value) {
TypedReference typedRef;
FieldInfo[] fieldsTemp=new FieldInfo[4];
FieldInfo[] fields=null;
int currentFieldIndex=0;
int[] arrayIndex = null;
ValueTypeFixupInfo currFixup=null;
Object fixupObj=holder.ObjectValue;
ObjectHolder originalHolder = holder;
BCLDebug.Assert(holder!=null, "[TypedReferenceBuilder.ctor]holder!=null");
BCLDebug.Assert(holder.RequiresValueTypeFixup, "[TypedReferenceBuilder.ctor]holder.RequiresValueTypeFixup");
//In order to get a TypedReference, we need to get a list of all of the FieldInfos to
//create the path from our outermost containing object down to the actual field which
//we'd like to set. This loop is used to build up that list.
while (holder.RequiresValueTypeFixup) {
BCLDebug.Trace("SER", "[DoValueTypeFixup] valueType fixsite = ", holder.ObjectValue, " fixobj=",value);
//Enlarge the array if required (this is actually fairly unlikely as it would require that we
//be nested more than 4 deep.
if ((currentFieldIndex + 1)>=fieldsTemp.Length) {
FieldInfo[] temp = new FieldInfo[fieldsTemp.Length * 2];
Array.Copy(fieldsTemp, temp, fieldsTemp.Length);
fieldsTemp = temp;
}
//Get the fixup information. If we have data for our parent field, add it to our list
//and continue the walk up to find the next outermost containing object. We cache the
//object that we have. In most cases, we could have just grabbed it after this loop finished.
//However, if the outermost containing object is an array, we need the object one further
//down the chain, so we have to do a lot of caching.
currFixup = holder.ValueFixup;
fixupObj = holder.ObjectValue; //Save the most derived
if (currFixup.ParentField!=null) {
FieldInfo parentField = currFixup.ParentField;
ObjectHolder tempHolder = FindObjectHolder(currFixup.ContainerID);
if (tempHolder.ObjectValue == null) {
break;
}
if (Nullable.GetUnderlyingType(parentField.FieldType) != null)
{
fieldsTemp[currentFieldIndex] = parentField.FieldType.GetField("value", BindingFlags.NonPublic|BindingFlags.Instance);
currentFieldIndex++;
}
fieldsTemp[currentFieldIndex] = parentField;
holder = tempHolder;
currentFieldIndex++;
} else {
//If we find an index into an array, save that information.
BCLDebug.Assert(currFixup.ParentIndex!=null, "[ObjectManager.DoValueTypeFixup]currFixup.ParentIndex!=null");
holder = FindObjectHolder(currFixup.ContainerID); //find the array to fix.
arrayIndex = currFixup.ParentIndex;
if (holder.ObjectValue==null) {
break;
}
break;
}
}
//If the outermost container isn't an array, we need to grab it. Otherwise, we just need to hang onto
//the boxed object that we already grabbed. We'll assign the boxed object back into the array as the
//last step.
if (!(holder.ObjectValue is Array) && holder.ObjectValue!=null) {
fixupObj = holder.ObjectValue;
BCLDebug.Assert(fixupObj!=null, "[ObjectManager.DoValueTypeFixup]FixupObj!=null");
}
#if false
//We thought that the valuetype had already been placed into it's parent, but when we started
//walking the track, we discovered a null, so that's clearly impossible. At this point, revert
//to just poking it into the most boxed version that we can.
if (fixupObj==null) {
fixupObj = originalHolder.ObjectValue;
FormatterServices.SerializationSetValue(memberToFix, fixupObj, value);
return true;
}
#endif
if (currentFieldIndex!=0) {
//MakeTypedReference requires an array of exactly the correct size that goes from the outermost object
//in to the innermost field. We currently have an array of arbitrary size that goes from the innermost
//object outwards. We create an array of the right size and do the copy.
fields = new FieldInfo[currentFieldIndex];
for (int i=0; i0,"temp.m_missingElementsRemaining>0");
temp.DecrementFixupsRemaining(this);
if (((temp.DirectlyDependentObjects))==0) {
BCLDebug.Trace("SER", "[DoNewlyRegisteredObjectFixups]Doing fixup for object ", temp.m_id);
BCLDebug.Trace("SER", "[DoNewlyRegisteredObjectFixups]ObjectValue ", ((temp.ObjectValue==null)?"":temp.ObjectValue));
// If this is null, we have the case where a fixup was registered for a child, the object
// required by the fixup was provided, and the object to be fixed hasn't yet been seen.
if (temp.ObjectValue!=null) {
CompleteObject(temp, true);
} else {
temp.MarkForCompletionWhenAvailable();
}
}
}
BCLDebug.Trace("SER", "[ObjectManager.DoNewlyRegisteredObjectFixups]Exiting.");
}
public virtual Object GetObject(long objectID) {
if (objectID<=0) {
throw new ArgumentOutOfRangeException("objectID", Environment.GetResourceString("ArgumentOutOfRange_ObjectID"));
}
//Find the bin in which we're interested. IObjectReference's shouldn't be returned -- the graph
//needs to link to the objects to which they refer, not to the references themselves.
ObjectHolder holder = FindObjectHolder(objectID);
BCLDebug.Trace("SER", "GetObject. objectID: ", objectID);
if (holder==null || holder.CanObjectValueChange) {
BCLDebug.Trace("SER", "GetObject. holder: null or IncompleteObjectReference");
return null;
}
BCLDebug.Trace("SER", "GetObject. holder contains: ", ((holder.ObjectValue==null)?"":holder.ObjectValue));
return holder.ObjectValue;
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public virtual void RegisterObject(Object obj, long objectID) {
RegisterObject(obj, objectID, null,0,null);
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public void RegisterObject(Object obj, long objectID, SerializationInfo info) {
RegisterObject(obj, objectID, info, 0, null);
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public void RegisterObject(Object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member) {
RegisterObject(obj, objectID, info, idOfContainingObj, member, null);
}
internal void RegisterString(String obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)
{
ObjectHolder temp;
BCLDebug.Assert(member == null || member is FieldInfo, "RegisterString - member is FieldInfo");
BCLDebug.Assert((FindObjectHolder(objectID) == null), "RegisterString - FindObjectHolder(objectID) == null");
temp = new ObjectHolder(obj, objectID, info, null, idOfContainingObj, (FieldInfo)member, null);
AddObjectHolder(temp);
return;
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public void RegisterObject(Object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex) {
ObjectHolder temp;
ISerializationSurrogate surrogate = null;
ISurrogateSelector useless;
if (obj==null) {
throw new ArgumentNullException("obj");
}
if (objectID<=0) {
throw new ArgumentOutOfRangeException("objectID", Environment.GetResourceString("ArgumentOutOfRange_ObjectID"));
}
if (member!=null && !(member is RuntimeFieldInfo) && !(member is SerializationFieldInfo)) {
throw new SerializationException(Environment.GetResourceString("Serialization_UnknownMemberInfo"));
}
if (m_selector != null)
{
Type selectorType=null;
if (CanCallGetType(obj)) {
selectorType = obj.GetType();
} else {
selectorType = typeof(MarshalByRefObject);
}
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]ID: ", objectID, "\tType: ", selectorType, "\tValue: ", obj);
//If we need a surrogate for this object, lets find it now.
surrogate = m_selector.GetSurrogate(selectorType, m_context, out useless);
}
//The object is interested in DeserializationEvents so lets register it.
if (obj is IDeserializationCallback) {
DeserializationEventHandler d = new DeserializationEventHandler(((IDeserializationCallback)obj).OnDeserialization);
AddOnDeserialization(d);
}
//Formatter developers may cache and reuse arrayIndex in their code.
//So that we don't get bitten by this, take a copy up front.
if (arrayIndex!=null) {
arrayIndex = (int[])arrayIndex.Clone();
}
temp = FindObjectHolder(objectID);
//This is the first time which we've seen the object, we need to create a new holder.
if (temp==null) {
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Adding a new object holder for ", objectID, "\tValueType: ", obj.GetType());
temp = new ObjectHolder(obj, objectID, info, surrogate, idOfContainingObj, (FieldInfo)member, arrayIndex);
AddObjectHolder(temp);
if (temp.RequiresDelayedFixup) {
SpecialFixupObjects.Add(temp);
}
// We cannot compute whether this has any fixups required or not
AddOnDeserialized(obj);
return;
}
//If the object isn't null, we've registered this before. Not good.
if (temp.ObjectValue!=null) {
throw new SerializationException(Environment.GetResourceString("Serialization_RegisterTwice"));
}
//Complete the data in the ObjectHolder
temp.UpdateData(obj, info, surrogate, idOfContainingObj, (FieldInfo)member, arrayIndex, this);
// The following case will only be true when somebody has registered a fixup on an object before
// registering the object itself. I don't believe that most well-behaved formatters will do this,
// but we need to allow it anyway. We will walk the list of fixups which have been recorded on
// the new object and fix those that we can. Because the user could still register later fixups
// on this object, we won't call any implementations of ISerializable now. If that's required,
// it will have to be handled by the code in DoFixups.
// README README: We have to do the UpdateData before
if (temp.DirectlyDependentObjects>0) {
CompleteObject(temp, false);
}
if (temp.RequiresDelayedFixup) {
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Tracking incomplete objref for element: ", temp.m_id);
SpecialFixupObjects.Add(temp);
}
if (temp.CompletelyFixed) {
//Here's where things get tricky. If this isn't an instance of IObjectReference, we need to walk it's fixup
//chain and decrement the counters on anything that has reached 0. Once we've notified all of the dependencies,
//we can simply clear the list of dependent objects.
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Calling DoNewlyRegisteredObjectFixups for element: ", temp.m_id);
DoNewlyRegisteredObjectFixups(temp);
temp.DependentObjects=null;
}
//Register the OnDeserialized methods to be invoked after deserialization is complete
if (temp.TotalDependentObjects > 0){
AddOnDeserialized(obj);
}
else {
RaiseOnDeserializedEvent(obj);
}
BCLDebug.Trace("SER", "[ObjectManager.RegisterObject]Exiting.");
}
/*=========================CompleteISerializableObject==========================
**Action: Completes an object implementing ISerializable. This will involve calling that
** objects constructor which takes an instance of ISerializable and a StreamingContext.
**Returns: void.
**Arguments: Obj -- The object to be completed.
** info -- The SerializationInfo containing all info for obj.
** context -- The streaming context in which the serialization is taking place.
**Exceptions: ArgumentNullException if obj is null
** ArgumentException if obj does not implement ISerializable.
==============================================================================*/
internal void CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context) {
RuntimeConstructorInfo constInfo = null;
if (obj==null) {
throw new ArgumentNullException("obj");
}
if (!(obj is ISerializable)) {
throw new ArgumentException(Environment.GetResourceString("Serialization_NotISer"));
}
Type t = obj.GetType();
try {
#if !FEATURE_PAL
if (t == TypeOfWindowsIdentity && m_isCrossAppDomain)
constInfo = GetConstructor(t, SIWindowsIdentityConstructorTypes);
else
#endif
constInfo = GetConstructor(t);
} catch (Exception e) {
BCLDebug.Trace("SER", "[CompleteISerializableObject]Unable to get constructor for: ", t);
BCLDebug.Trace("SER", "[CompleteISerializableObject]Stack trace was: ", e);
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ConstructorNotFound"), t), e);
}
constInfo.SerializationInvoke(obj, info, context);
}
/*================================GetConstructor================================
**Action:
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
internal static RuntimeConstructorInfo GetConstructor(Type t) {
return GetConstructor(t, SIConstructorTypes);
}
internal static RuntimeConstructorInfo GetConstructor(Type t, Type[] ctorParams) {
BCLDebug.Assert(t!=null, "[GetConstructor]t!=null");
BCLDebug.Assert(t is RuntimeType, "[GetConstructor]t is RuntimeType");
RuntimeConstructorInfo ci;
if ((ci=(RuntimeConstructorInfo)t.Cache[CacheObjType.ConstructorInfo])==null) {
RuntimeType rt = (RuntimeType)t;
ci = rt.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, CallingConventions.Any, ctorParams, null) as RuntimeConstructorInfo;
if (ci==null) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ConstructorNotFound"), t.FullName));
}
t.Cache[CacheObjType.ConstructorInfo] = ci;
}
return ci;
}
public virtual void DoFixups() {
ObjectHolder temp;
int fixupCount=-1;
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Entering");
//The first thing that we need to do is fixup all of the objects which implement
//IObjectReference. This is complicated by the fact that we need to deal with IReferenceObjects
//objects that have a reference to an object implementing IObjectReference. We continually
//walk over the list of objects until we've completed all of the object references or until
//we can't resolve any more (which may happen if we have two objects implementing IObjectReference
//which have a circular dependency on each other). We don't explicitly catch the later case here,
//it will be caught when we try to do the rest of the fixups and discover that we have some that
//can't be completed.
while (fixupCount!=0) {
fixupCount=0;
//Walk all of the IObjectReferences and ensure that they've been properly completed.
ObjectHolderListEnumerator fixupObjectsEnum = SpecialFixupObjects.GetFixupEnumerator();
while (fixupObjectsEnum.MoveNext()) {
temp = fixupObjectsEnum.Current;
if (temp.ObjectValue == null) {
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Object with id: ", temp.m_id, " not found.");
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_ObjectNotSupplied"), temp.m_id));
}
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Looking at object with id: ", temp.m_id, " which has ",
temp.TotalDependentObjects, " Total Dependent Fixups, but only ",
(temp.DependentObjects==null)?0:temp.DependentObjects.Count,
" directly dependent objects. Has it been fixed? ", temp.CompletelyFixed);
if (temp.TotalDependentObjects==0) {
if (temp.RequiresSerInfoFixup) {
FixupSpecialObject(temp);
fixupCount++;
} else if (!temp.IsIncompleteObjectReference) {
CompleteObject(temp, true);
}
if (temp.IsIncompleteObjectReference && ResolveObjectReference(temp)) {
fixupCount++;
}
}
}
}
BCLDebug.Assert(m_fixupCount>=0,"[ObjectManager.DoFixups]m_fixupCount>=0");
//If our count is 0, we're done and should just return
if (m_fixupCount==0) {
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]All fixups completed. We don't need to walk the list.");
if (TopObject is TypeLoadExceptionHolder)
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_TypeLoadFailure"), ((TypeLoadExceptionHolder)TopObject).TypeName));
return;
}
//If our count isn't 0, we had at least one case where an object referenced another object twice.
//Walk the entire list until the count is 0 or until we find an object which we can't complete.
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Remaining object length is: ", m_objects.Length);
for (int i=0; i0 /*|| temp.m_missingElements!=null*/) {
BCLDebug.Trace("SER", "[ObjectManager.DoFixups]Doing a delayed fixup on object ", temp.m_id);
CompleteObject(temp, true);
}
temp = temp.m_next;
}
if (m_fixupCount==0) {
return;
}
}
// this assert can be trigered by user code that manages fixups manually
BCLDebug.Correctness(false, "[ObjectManager.DoFixups] Fixup counting is incorrect.");
throw new SerializationException(Environment.GetResourceString("Serialization_IncorrectNumberOfFixups"));
}
/*================================RegisterFixup=================================
**Action: Do the actual grunt work of recording a fixup and registering the dependency.
** Create the necessary ObjectHolders and use them to do the addition.
**Returns: void
**Arguments: fixup -- The FixupHolder to be added.
** objectToBeFixed -- The id of the object requiring the fixup.
** objectRequired -- The id of the object required to do the fixup.
**Exceptions: None. This is internal-only, so all checking should have been done by this time.
==============================================================================*/
private void RegisterFixup(FixupHolder fixup, long objectToBeFixed, long objectRequired) {
//Record the fixup with the object that needs it.
ObjectHolder ohToBeFixed = FindOrCreateObjectHolder(objectToBeFixed);
ObjectHolder ohRequired;
if (ohToBeFixed.RequiresSerInfoFixup && fixup.m_fixupType == FixupHolder.MemberFixup) {
throw new SerializationException(Environment.GetResourceString("Serialization_InvalidFixupType"));
}
//Add the fixup to the list.
ohToBeFixed.AddFixup(fixup, this);
//Find the object on which we're dependent and note the dependency.
//These dependencies will be processed when the object is supplied.
ohRequired = FindOrCreateObjectHolder(objectRequired);
ohRequired.AddDependency(objectToBeFixed);
m_fixupCount++;
}
public virtual void RecordFixup(long objectToBeFixed, MemberInfo member, long objectRequired) {
//Verify our arguments
if (objectToBeFixed<=0 || objectRequired<=0) {
throw new ArgumentOutOfRangeException(((objectToBeFixed<=0)?"objectToBeFixed":"objectRequired"),
Environment.GetResourceString("Serialization_IdTooSmall"));
}
if (member==null) {
throw new ArgumentNullException("member");
}
if (!(member is RuntimeFieldInfo) && !(member is SerializationFieldInfo)) {
throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_InvalidType"), member.GetType().ToString()));
}
BCLDebug.Trace("SER", "RecordFixup. ObjectToBeFixed: ", objectToBeFixed, "\tMember: ", member.Name, "\tRequiredObject: ", objectRequired);
//Create a new fixup holder
FixupHolder fixup = new FixupHolder(objectRequired, member, FixupHolder.MemberFixup);
RegisterFixup(fixup, objectToBeFixed, objectRequired);
}
/*==============================RecordDelayedFixup==============================
**Action:
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
public virtual void RecordDelayedFixup(long objectToBeFixed, String memberName, long objectRequired) {
//Verify our arguments
if (objectToBeFixed<=0 || objectRequired<=0) {
throw new ArgumentOutOfRangeException(((objectToBeFixed<=0)?"objectToBeFixed":"objectRequired"),
Environment.GetResourceString("Serialization_IdTooSmall"));
}
if (memberName==null) {
throw new ArgumentNullException("memberName");
}
BCLDebug.Trace("SER", "RecordDelayedFixup. ObjectToBeFixed: ", objectToBeFixed, "\tMember: ", memberName, "\tRequiredObject: ", objectRequired);
//Create a new fixup holder
FixupHolder fixup = new FixupHolder(objectRequired, memberName, FixupHolder.DelayedFixup);
RegisterFixup(fixup, objectToBeFixed, objectRequired);
}
/*===========================RecordArrayElementFixup============================
**Action:
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
public virtual void RecordArrayElementFixup(long arrayToBeFixed, int index, long objectRequired) {
int[] indexArray = new int[1];
indexArray[0]=index;
BCLDebug.Trace("SER", "RecordArrayElementFixup. ObjectToBeFixed: ", arrayToBeFixed, "\tIndex: ", index, "\tRequiredObject: ", objectRequired);
RecordArrayElementFixup(arrayToBeFixed, indexArray, objectRequired);
}
public virtual void RecordArrayElementFixup(long arrayToBeFixed, int[] indices, long objectRequired) {
//Verify our arguments
if (arrayToBeFixed<=0 || objectRequired<=0) {
throw new ArgumentOutOfRangeException(((arrayToBeFixed<=0)?"objectToBeFixed":"objectRequired"),
Environment.GetResourceString("Serialization_IdTooSmall"));
}
if (indices==null) {
throw new ArgumentNullException("indices");
}
BCLDebug.Trace("SER", "RecordArrayElementFixup. ArrayToBeFixed: ", arrayToBeFixed, "\tRequiredObject: ", objectRequired);
FixupHolder fixup = new FixupHolder(objectRequired, indices, FixupHolder.ArrayFixup);
RegisterFixup(fixup, arrayToBeFixed, objectRequired);
}
/*==========================RaiseDeserializationEvent===========================
**Action:Raises the deserialization event to any registered object which implements
** IDeserializationCallback.
**Returns: void
**Arguments: none
**Exceptions: None
==============================================================================*/
public virtual void RaiseDeserializationEvent() {
// Invoke OnDerserialized event if applicable
if (m_onDeserializedHandler != null) {
m_onDeserializedHandler(m_context);
}
if (m_onDeserializationHandler!=null) {
m_onDeserializationHandler(null);
}
}
internal virtual void AddOnDeserialization(DeserializationEventHandler handler) {
m_onDeserializationHandler = (DeserializationEventHandler)Delegate.Combine(m_onDeserializationHandler, handler);
}
internal virtual void RemoveOnDeserialization(DeserializationEventHandler handler) {
m_onDeserializationHandler = (DeserializationEventHandler)Delegate.Remove(m_onDeserializationHandler, handler);
}
internal virtual void AddOnDeserialized(Object obj)
{
SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType());
m_onDeserializedHandler = cache.AddOnDeserialized(obj, m_onDeserializedHandler);
}
internal virtual void RaiseOnDeserializedEvent(Object obj)
{
SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType());
cache.InvokeOnDeserialized(obj, m_context);
}
public void RaiseOnDeserializingEvent(Object obj)
{
// Run the OnDeserializing methods
SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType());
cache.InvokeOnDeserializing(obj, m_context);
}
}
internal sealed class ObjectHolder {
internal const int INCOMPLETE_OBJECT_REFERENCE = 0x0001;
internal const int HAS_ISERIALIZABLE = 0x0002;
internal const int HAS_SURROGATE = 0x0004;
internal const int REQUIRES_VALUETYPE_FIXUP = 0x0008;
internal const int REQUIRES_DELAYED_FIXUP = HAS_ISERIALIZABLE | HAS_SURROGATE | INCOMPLETE_OBJECT_REFERENCE;
internal const int SER_INFO_FIXED = 0x4000;
internal const int VALUETYPE_FIXUP_PERFORMED = 0x8000;
private Object m_object;
internal long m_id;
private int m_missingElementsRemaining;
private int m_missingDecendents;
internal SerializationInfo m_serInfo;
internal ISerializationSurrogate m_surrogate;
internal FixupHolderList m_missingElements;
internal LongList m_dependentObjects;
internal ObjectHolder m_next;
internal int m_flags;
private bool m_markForFixupWhenAvailable;
private ValueTypeFixupInfo m_valueFixup;
private TypeLoadExceptionHolder m_typeLoad = null;
private bool m_reachable = false;
internal ObjectHolder(long objID)
: this(null, objID, null, null, 0, null, null) {
}
internal ObjectHolder(Object obj, long objID, SerializationInfo info,
ISerializationSurrogate surrogate, long idOfContainingObj, FieldInfo field, int[] arrayIndex) {
BCLDebug.Assert(objID>=0,"objID>=0");
m_object=obj; //May be null;
m_id=objID;
m_flags=0;
m_missingElementsRemaining=0;
m_missingDecendents = 0;
m_dependentObjects=null;
m_next=null;
m_serInfo = info;
m_surrogate = surrogate;
m_markForFixupWhenAvailable = false;
if (obj is TypeLoadExceptionHolder)
{
m_typeLoad = (TypeLoadExceptionHolder)obj;
}
if (idOfContainingObj!=0 && ((field!=null && field.FieldType.IsValueType) || arrayIndex!=null)) {
if (idOfContainingObj == objID) {
throw new SerializationException(Environment.GetResourceString("Serialization_ParentChildIdentical"));
}
m_valueFixup = new ValueTypeFixupInfo(idOfContainingObj, field, arrayIndex);
}
SetFlags();
}
internal ObjectHolder(String obj, long objID, SerializationInfo info,
ISerializationSurrogate surrogate, long idOfContainingObj, FieldInfo field, int[] arrayIndex) {
BCLDebug.Assert(objID>=0,"objID>=0");
m_object=obj; //May be null;
m_id=objID;
m_flags=0;
m_missingElementsRemaining=0;
m_missingDecendents = 0;
m_dependentObjects=null;
m_next=null;
m_serInfo = info;
m_surrogate = surrogate;
m_markForFixupWhenAvailable = false;
if (idOfContainingObj!=0 && arrayIndex!=null) {
m_valueFixup = new ValueTypeFixupInfo(idOfContainingObj, field, arrayIndex);
}
if (m_valueFixup!=null) {
m_flags|=REQUIRES_VALUETYPE_FIXUP;
}
}
private void IncrementDescendentFixups(int amount) {
m_missingDecendents+=amount;
}
internal void DecrementFixupsRemaining(ObjectManager manager) {
m_missingElementsRemaining--;
if (RequiresValueTypeFixup) {
UpdateDescendentDependencyChain(-1, manager);
}
}
/*===============================RemoveDependency===============================
**Action: Removes a dependency of the object represented in this holder.
** This is normally the result of the dependency having been filled when
** the object is going to be only partially completed. If we plan to fully
** update the object, we do not take the work to do this.
**Returns: void.
**Arguments: id -- The id of the object for which to remove the dependency.
**Exceptions: None, error handling through asserts.
==============================================================================*/
internal void RemoveDependency(long id) {
BCLDebug.Assert(m_dependentObjects!=null, "[ObjectHolder.RemoveDependency]m_dependentObjects!=null");
BCLDebug.Assert(id>=0, "[ObjectHolder.RemoveDependency]id>=0");
m_dependentObjects.RemoveElement(id);
}
/*===================================AddFixup===================================
**Action: Note a fixup that has to be done before this object can be completed.
** Fixups are things that need to happen when other objects in the graph
** are added. Dependencies are things that need to happen when this object
** is added.
**Returns: void
**Arguments: fixup -- The fixup holder containing enough information to complete the fixup.
**Exceptions: None.
==============================================================================*/
internal void AddFixup(FixupHolder fixup, ObjectManager manager) {
if (m_missingElements==null) {
m_missingElements = new FixupHolderList();
}
m_missingElements.Add(fixup);
m_missingElementsRemaining++;
if (RequiresValueTypeFixup) {
UpdateDescendentDependencyChain(1, manager);
}
}
/*==========================UpdateTotalDependencyChain==========================
**Action: Updates the total list of dependencies to account for a fixup being added
** or completed in a child value class. This will update all value classes
** containing that child and the object which contains all of them.
**Returns: void
**Arguments: amount -- the amount by which to increment (or decrement) the dependency chain.
** manager -- The ObjectManager used to lookup other objects up the chain.
**Exceptions: None. Asserts only.
==============================================================================*/
private void UpdateDescendentDependencyChain(int amount, ObjectManager manager) {
ObjectHolder holder = this;
//This loop walks one more object up the chain than there are valuetypes. This
//is because we need to increment the TotalFixups in the holders as well.
do {
holder = manager.FindOrCreateObjectHolder(holder.ContainerID);
BCLDebug.Trace("SER", "[ObjectManager.UpdateDescendentDependencyChain]Looking for holder with id: ", holder.ContainerID);
BCLDebug.Assert(holder!=null, "[ObjectHolder.UpdateTotalDependencyChain]holder!=null");
holder.IncrementDescendentFixups(amount);
} while (holder.RequiresValueTypeFixup);
}
/*================================AddDependency=================================
**Action: Note an object which is dependent on the one which will be contained in
** this ObjectHolder. Dependencies should only be added if the object hasn't
** yet been added. NB: An incomplete object counts as having no object.
**Returns: void
**Arguments: dependentObject -- the id of the object which is dependent on this object being provided.
**Exceptions: None.
==============================================================================*/
internal void AddDependency(long dependentObject) {
if (m_dependentObjects==null) {
m_dependentObjects = new LongList();
}
m_dependentObjects.Add(dependentObject);
}
/*==================================UpdateData==================================
**Action: Update the data in the object holder. This should be called when the object
** is finally registered. Presumably the ObjectHolder was created to track
** some dependencies or preregistered fixups and we now need to actually record the
** object and other associated data. We take this opportunity to set the flags
** so that we can do some faster processing in the future.
**Returns: void
**Arguments: obj -- The object being held by this object holder. (This should no longer be null).
** info --The SerializationInfo associated with this object, only required if we're doing delayed fixups.
** surrogate -- The surrogate handling this object. May be null.
** idOfContainer -- The id of the object containing this one if this is a valuetype.
** member -- the MemberInfo of this object's position in it's container if this is a valuetype.
** manager -- the ObjectManager being used to track these ObjectHolders.
**Exceptions: None. Asserts only.
==============================================================================*/
internal void UpdateData(Object obj, SerializationInfo info, ISerializationSurrogate surrogate, long idOfContainer, FieldInfo field, int[] arrayIndex, ObjectManager manager) {
BCLDebug.Assert(obj!=null,"obj!=null");
BCLDebug.Assert(m_id>0,"m_id>0");
//Record the fields that we can.
SetObjectValue(obj, manager);
m_serInfo = info;
m_surrogate = surrogate;
if (idOfContainer!=0 && ((field!=null && field.FieldType.IsValueType) || arrayIndex!=null)) {
if (idOfContainer == m_id) {
throw new SerializationException(Environment.GetResourceString("Serialization_ParentChildIdentical"));
}
m_valueFixup = new ValueTypeFixupInfo(idOfContainer, field, arrayIndex);
}
SetFlags();
if (RequiresValueTypeFixup) {
UpdateDescendentDependencyChain(m_missingElementsRemaining, manager);
}
}
internal void MarkForCompletionWhenAvailable() {
m_markForFixupWhenAvailable = true;
}
/*===================================SetFlags===================================
**Action: An internal-only routine to set the flags based upon the data contained in
** the ObjectHolder
**Returns: Void
**Arguments: None
**Exceptions: None
==============================================================================*/
internal void SetFlags() {
if (m_object is IObjectReference) {
m_flags|=INCOMPLETE_OBJECT_REFERENCE;
}
m_flags &= ~(HAS_ISERIALIZABLE | HAS_SURROGATE);
if (m_surrogate!=null)
m_flags|=HAS_SURROGATE;
else if (m_object is ISerializable)
m_flags|=HAS_ISERIALIZABLE;
if (m_valueFixup!=null) {
m_flags|=REQUIRES_VALUETYPE_FIXUP;
}
}
internal bool IsIncompleteObjectReference {
get { return (m_flags & (INCOMPLETE_OBJECT_REFERENCE /*| HAS_SURROGATE*/)) != 0; }
set {
if (value) {
m_flags|=INCOMPLETE_OBJECT_REFERENCE;
} else {
m_flags&=~INCOMPLETE_OBJECT_REFERENCE;
}
}
}
internal bool RequiresDelayedFixup {
get { return (m_flags & REQUIRES_DELAYED_FIXUP)!=0; }
}
internal bool RequiresValueTypeFixup {
get { return (m_flags & REQUIRES_VALUETYPE_FIXUP)!=0; }
}
// ValueTypes which require fixups are initially handed to the ObjectManager
// as boxed objects. When they're still boxed objects, we should just do fixups
// on them like we would any other object. As soon as they're pushed into their
// containing object we set ValueTypeFixupPerformed to true and have to go through
// a more complicated path to set fixed up valuetype objects.
// We check whether or not there are any dependent objects.
internal bool ValueTypeFixupPerformed {
get {
BCLDebug.Trace("SER", "[ObjectManager.ValueTypeFixupPerformed]Flags: ", m_flags & VALUETYPE_FIXUP_PERFORMED);
BCLDebug.Trace("SER", "[ObjectManager.ValueTypeFixupPerformed]DependentObjects: ", (m_dependentObjects==null)?"":m_dependentObjects.Count.ToString());
return ( ((m_flags & VALUETYPE_FIXUP_PERFORMED)!=0)||
(m_object!=null && ((m_dependentObjects==null) || m_dependentObjects.Count==0))); }
set {
if (value) {
m_flags|=VALUETYPE_FIXUP_PERFORMED;
}
}
}
internal bool HasISerializable {
get {
return (m_flags & HAS_ISERIALIZABLE)!=0;
}
}
internal bool HasSurrogate {
get { return (m_flags & HAS_SURROGATE)!=0; }
}
internal bool CanSurrogatedObjectValueChange
{
get
{
return (m_surrogate == null || m_surrogate.GetType() != typeof(SurrogateForCyclicalReference));
}
}
internal bool CanObjectValueChange
{
get
{
if (IsIncompleteObjectReference)
return true;
if (HasSurrogate)
return CanSurrogatedObjectValueChange;
return false;
}
}
internal int DirectlyDependentObjects {
get {
return m_missingElementsRemaining;
}
}
internal int TotalDependentObjects {
get {
return m_missingElementsRemaining + m_missingDecendents;
}
}
internal bool Reachable {
get { return m_reachable; }
set { m_reachable = value; }
}
internal bool TypeLoadExceptionReachable {
get { return m_typeLoad != null; }
}
internal TypeLoadExceptionHolder TypeLoadException {
get { return m_typeLoad; }
set { m_typeLoad = value; }
}
internal Object ObjectValue {
get {
return m_object;
}
}
internal void SetObjectValue(Object obj, ObjectManager manager) {
m_object = obj;
if (obj == manager.TopObject)
m_reachable = true;
if (obj is TypeLoadExceptionHolder)
m_typeLoad = (TypeLoadExceptionHolder)obj;
if (m_markForFixupWhenAvailable) {
manager.CompleteObject(this, true);
}
}
internal SerializationInfo SerializationInfo {
get {
return m_serInfo;
}
set {
m_serInfo = value;
}
}
internal ISerializationSurrogate Surrogate {
get {
return m_surrogate;
}
}
internal LongList DependentObjects {
get {
return m_dependentObjects;
}
set {
m_dependentObjects = value;
}
}
internal bool RequiresSerInfoFixup {
get {
if (((m_flags & HAS_SURROGATE)==0) && ((m_flags & HAS_ISERIALIZABLE)==0)) {
return false;
}
return (m_flags & SER_INFO_FIXED)==0;
}
set {
if (!value) {
m_flags|=SER_INFO_FIXED;
} else {
m_flags&=~SER_INFO_FIXED;
}
}
}
internal ValueTypeFixupInfo ValueFixup {
get {
return m_valueFixup;
}
}
internal bool CompletelyFixed {
get {
return (!RequiresSerInfoFixup && !IsIncompleteObjectReference);
}
}
internal long ContainerID {
get {
if (m_valueFixup!=null) {
return m_valueFixup.ContainerID;
}
return 0;
}
}
}
[Serializable()]
internal class FixupHolder {
internal const int ArrayFixup=0x1;
internal const int MemberFixup=0x2;
internal const int DelayedFixup=0x4;
internal long m_id;
internal Object m_fixupInfo; //This is either an array index, a String, or a MemberInfo
internal int m_fixupType;
internal FixupHolder(long id, Object fixupInfo, int fixupType) {
BCLDebug.Assert(id>0,"id>0");
BCLDebug.Assert(fixupInfo!=null,"fixupInfo!=null");
BCLDebug.Assert(fixupType==ArrayFixup || fixupType == MemberFixup || fixupType==DelayedFixup,"fixupType==ArrayFixup || fixupType == MemberFixup || fixupType==DelayedFixup");
m_id = id;
m_fixupInfo = fixupInfo;
m_fixupType = fixupType;
}
}
[Serializable()]
internal class FixupHolderList {
internal const int InitialSize = 2;
internal FixupHolder[] m_values;
internal int m_count;
internal FixupHolderList() : this(InitialSize) {
}
internal FixupHolderList(int startingSize) {
m_count=0;
m_values = new FixupHolder[startingSize];
}
internal virtual void Add(long id, Object fixupInfo) {
if (m_count==m_values.Length) {
EnlargeArray();
}
m_values[m_count].m_id=id;
m_values[m_count++].m_fixupInfo = fixupInfo;
}
internal virtual void Add(FixupHolder fixup) {
if (m_count==m_values.Length) {
EnlargeArray();
}
m_values[m_count++]=fixup;
}
private void EnlargeArray() {
int newLength = m_values.Length*2;
if (newLength<0) {
if (newLength==Int32.MaxValue) {
throw new SerializationException(Environment.GetResourceString("Serialization_TooManyElements"));
}
newLength=Int32.MaxValue;
}
FixupHolder[] temp = new FixupHolder[newLength];
Array.Copy(m_values, temp, m_count);
m_values=temp;
}
}
[Serializable()]
internal class LongList {
private const int InitialSize = 2;
private long [] m_values;
private int m_count; //The total number of valid items still in the list;
private int m_totalItems; //The total number of allocated entries.
//This includes space for items which have been marked as deleted.
private int m_currentItem; //Used when doing an enumeration over the list.
//
// An m_currentItem of -1 indicates that the enumeration hasn't been started.
// An m_values[xx] of -1 indicates that the item has been deleted.
//
internal LongList() : this(InitialSize) {
}
internal LongList(int startingSize) {
m_count=0;
m_totalItems = 0;
m_values = new long[startingSize];
}
internal void Add(long value) {
if (m_totalItems==m_values.Length) {
EnlargeArray();
}
m_values[m_totalItems++]=value;
m_count++;
}
internal int Count {
get {
return m_count;
}
}
internal void StartEnumeration() {
m_currentItem = -1;
}
internal bool MoveNext() {
while (++m_currentItem < m_totalItems && m_values[m_currentItem]==-1) {
}
if (m_currentItem==m_totalItems) {
return false;
}
return true;
}
internal long Current {
get {
BCLDebug.Assert(m_currentItem!=-1, "[LongList.Current]m_currentItem!=-1");
BCLDebug.Assert(m_values[m_currentItem]!=-1, "[LongList.Current]m_values[m_currentItem]!=-1");
return m_values[m_currentItem];
}
}
internal bool RemoveElement(long value) {
int i;
for (i=0; i0 && startingSize<0x1000,"startingSize>0 && startingSize<0x1000");
m_count =0;
m_values = new ObjectHolder[startingSize];
}
internal virtual void Add(ObjectHolder value) {
if (m_count==m_values.Length) {
EnlargeArray();
}
m_values[m_count++]=value;
}
internal ObjectHolderListEnumerator GetFixupEnumerator() {
return new ObjectHolderListEnumerator(this, true);
}
private void EnlargeArray() {
BCLDebug.Trace("SER", "[ObjectHolderList.EnlargeArray]Enlarging array of size ", m_values.Length);
int newLength = m_values.Length*2;
if (newLength<0) {
if (newLength==Int32.MaxValue) {
throw new SerializationException(Environment.GetResourceString("Serialization_TooManyElements"));
}
newLength=Int32.MaxValue;
}
ObjectHolder[] temp = new ObjectHolder[newLength];
Array.Copy(m_values, temp, m_count);
m_values = temp;
}
internal int Version {
get {
return m_count;
}
}
internal int Count {
get {
return m_count;
}
}
}
internal class ObjectHolderListEnumerator {
bool m_isFixupEnumerator;
ObjectHolderList m_list;
int m_startingVersion;
int m_currPos;
internal ObjectHolderListEnumerator(ObjectHolderList list, bool isFixupEnumerator) {
BCLDebug.Assert(list!=null, "[ObjectHolderListEnumerator.ctor]list!=null");
m_list = list;
m_startingVersion = m_list.Version;
m_currPos=-1;
m_isFixupEnumerator = isFixupEnumerator;
}
internal bool MoveNext() {
BCLDebug.Assert(m_startingVersion==m_list.Version, "[ObjectHolderListEnumerator.MoveNext]m_startingVersion==m_list.Version");
if (m_isFixupEnumerator) {
while (++m_currPos < m_list.Count && m_list.m_values[m_currPos].CompletelyFixed) {
}
if (m_currPos==m_list.Count) {
return false;
}
return true;
} else {
m_currPos++;
if (m_currPos==m_list.Count) {
return false;
}
return true;
}
}
internal ObjectHolder Current {
get {
BCLDebug.Assert(m_currPos!=-1, "[ObjectHolderListEnumerator.Current]m_currPos!=-1");
BCLDebug.Assert(m_currPos
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- sqlstateclientmanager.cs
- NamespaceMapping.cs
- PrimarySelectionGlyph.cs
- MatrixTransform.cs
- VisualStyleInformation.cs
- DrawingVisual.cs
- TemplateBuilder.cs
- WizardPanel.cs
- LineUtil.cs
- ActiveDocumentEvent.cs
- XmlEncoding.cs
- CodeDefaultValueExpression.cs
- CapabilitiesUse.cs
- AddingNewEventArgs.cs
- ConfigPathUtility.cs
- EntityParameter.cs
- Clipboard.cs
- ErrorRuntimeConfig.cs
- ControlCollection.cs
- SafeRightsManagementSessionHandle.cs
- NavigationPropertyEmitter.cs
- XPathPatternParser.cs
- NativeCompoundFileAPIs.cs
- Schema.cs
- log.cs
- LinkDescriptor.cs
- ListBox.cs
- WebRequestModuleElement.cs
- KerberosReceiverSecurityToken.cs
- DataProtection.cs
- cookie.cs
- SafeLibraryHandle.cs
- ModelItemKeyValuePair.cs
- SecurityDescriptor.cs
- ReadOnlyDictionary.cs
- FieldAccessException.cs
- MDIWindowDialog.cs
- ClipboardData.cs
- RadioButton.cs
- FormViewInsertedEventArgs.cs
- TextParaLineResult.cs
- CompiledQueryCacheKey.cs
- HMACSHA256.cs
- KeyManager.cs
- DefaultPerformanceCounters.cs
- WebPartTransformerAttribute.cs
- TeredoHelper.cs
- SponsorHelper.cs
- Configuration.cs
- MetadataPropertyvalue.cs
- TransactionsSectionGroup.cs
- AlphaSortedEnumConverter.cs
- ListViewPagedDataSource.cs
- SHA1CryptoServiceProvider.cs
- DataGridColumnCollection.cs
- TypeDescriptor.cs
- BinaryReader.cs
- LocatorPart.cs
- NameGenerator.cs
- ConstructorExpr.cs
- CollectionChangeEventArgs.cs
- TransactionCache.cs
- ClientApiGenerator.cs
- AttributeXamlType.cs
- ActiveXSite.cs
- DateTimeOffset.cs
- DocumentGridPage.cs
- RuntimeCompatibilityAttribute.cs
- BamlLocalizabilityResolver.cs
- QilSortKey.cs
- PersonalizableTypeEntry.cs
- MultiTrigger.cs
- BooleanFunctions.cs
- CategoryAttribute.cs
- XmlDocumentType.cs
- storepermissionattribute.cs
- LogAppendAsyncResult.cs
- Border.cs
- Helper.cs
- serverconfig.cs
- XhtmlConformanceSection.cs
- ColorInterpolationModeValidation.cs
- InputLanguageSource.cs
- DataGridCell.cs
- RelatedImageListAttribute.cs
- MimeBasePart.cs
- ValidationErrorCollection.cs
- StringArrayConverter.cs
- ContainsSearchOperator.cs
- PrtCap_Builder.cs
- TypeUsageBuilder.cs
- FieldNameLookup.cs
- SecurityManager.cs
- SmtpNegotiateAuthenticationModule.cs
- BooleanKeyFrameCollection.cs
- GridViewRow.cs
- ImageButton.cs
- UIElement3DAutomationPeer.cs
- IntegerFacetDescriptionElement.cs
- EdmError.cs