internal void CompleteObject(ObjectHolder holder, bool bObjectFullyComplete)
{
FixupHolderList fixups = holder._missingElements;
FixupHolder currentFixup;
SerializationInfo si;
object fixupInfo = null;
ObjectHolder tempObjectHolder = null;
int fixupsPerformed = 0;
Debug.Assert(holder != null, "[ObjectManager.CompleteObject]holder.m_object!=null");
if (holder.ObjectValue == null)
{
throw new SerializationException(SR.Format(SR.Serialization_MissingObject, holder._id));
}
if (fixups == null)
{
return;
}
//If either one of these conditions is true, we need to update the data in the
//SerializationInfo before calling SetObjectData.
if (holder.HasSurrogate || holder.HasISerializable)
{
si = holder._serInfo;
if (si == null)
{
throw new SerializationException(SR.Serialization_InvalidFixupDiscovered);
}
//Walk each of the fixups and complete the name-value pair in the SerializationInfo.
if (fixups != null)
{
for (int i = 0; i < fixups._count; i++)
{
if (fixups._values[i] == null)
{
continue;
}
Debug.Assert(fixups._values[i]._fixupType == FixupHolder.DelayedFixup, "fixups.m_values[i].m_fixupType==FixupHolder.DelayedFixup");
if (GetCompletionInfo(fixups._values[i], out tempObjectHolder, out fixupInfo, bObjectFullyComplete))
{
//Walk the SerializationInfo and find the member needing completion. All we have to do
//at this point is set the member into the Object
object holderValue = tempObjectHolder.ObjectValue;
if (CanCallGetType(holderValue))
{
si.UpdateValue((string)fixupInfo, holderValue, holderValue.GetType());
}
else
{
si.UpdateValue((string)fixupInfo, holderValue, typeof(MarshalByRefObject));
}
//Decrement our total number of fixups left to do.
fixupsPerformed++;
fixups._values[i] = null;
if (!bObjectFullyComplete)
{
holder.DecrementFixupsRemaining(this);
tempObjectHolder.RemoveDependency(holder._id);
}
}
}
}
}
else
{
for (int i = 0; i < fixups._count; i++)
{
currentFixup = fixups._values[i];
if (currentFixup == null)
{
continue;
}
if (GetCompletionInfo(currentFixup, out tempObjectHolder, out fixupInfo, bObjectFullyComplete))
{
// Check to make sure we are not both reachable from the topObject
// and there was a typeloadexception
if (tempObjectHolder.TypeLoadExceptionReachable)
{
holder.TypeLoadException = tempObjectHolder.TypeLoadException;
// If the holder is both reachable and typeloadexceptionreachable
// throw an exception with the type name
if (holder.Reachable)
{
throw new SerializationException(SR.Format(SR.Serialization_TypeLoadFailure, holder.TypeLoadException.TypeName));
}
}
// If the current holder is reachable, mark the dependant reachable as well
if (holder.Reachable)
{
tempObjectHolder.Reachable = true;
}
//There are two types of fixups that we could be doing: array or member.
//Delayed Fixups should be handled by the above branch.
switch (currentFixup._fixupType)
{
case FixupHolder.ArrayFixup:
Debug.Assert(holder.ObjectValue is Array, "holder.ObjectValue is Array");
if (holder.RequiresValueTypeFixup)
{
throw new SerializationException(SR.Serialization_ValueTypeFixup);
}
else
{
((Array)(holder.ObjectValue)).SetValue(tempObjectHolder.ObjectValue, ((int[])fixupInfo));
}
break;
case FixupHolder.MemberFixup:
Debug.Assert(fixupInfo is MemberInfo, "fixupInfo is MemberInfo");
//Fixup the member directly.
MemberInfo tempMember = (MemberInfo)fixupInfo;
if (tempMember is FieldInfo)
{
// If we have a valuetype that's been boxed to an object and requires a fixup,
// there are two possible states:
// (a)The valuetype has never been fixed up into it's container. In this case, we should
// just fix up the boxed valuetype. The task of pushing that valuetype into it's container
// will be handled later. This case is handled by the else clause of the following statement.
// (b)The valuetype has already been inserted into it's container. In that case, we need
// to go through the more complicated path laid out in DoValueTypeFixup. We can tell that the
// valuetype has already been inserted into it's container because we set ValueTypeFixupPerformed
// to true when we do this.
if (holder.RequiresValueTypeFixup && holder.ValueTypeFixupPerformed)
{
if (!DoValueTypeFixup((FieldInfo)tempMember, holder, tempObjectHolder.ObjectValue))
{
throw new SerializationException(SR.Serialization_PartialValueTypeFixup);
}
}
else
{
FormatterServices.SerializationSetValue(tempMember, holder.ObjectValue, tempObjectHolder.ObjectValue);
}
if (tempObjectHolder.RequiresValueTypeFixup)
{
tempObjectHolder.ValueTypeFixupPerformed = true;
}
}
else
{
throw new SerializationException(SR.Serialization_UnableToFixup);
}
break;
default:
throw new SerializationException(SR.Serialization_UnableToFixup);
}
//Decrement our total number of fixups left to do.
fixupsPerformed++;
fixups._values[i] = null;
if (!bObjectFullyComplete)
{
holder.DecrementFixupsRemaining(this);
tempObjectHolder.RemoveDependency(holder._id);
}
}
}
}
_fixupCount -= fixupsPerformed;
if (fixups._count == fixupsPerformed)
{
holder._missingElements = null;
}
}