private bool ResolveObjectReference(ObjectHolder holder)
{
object tempObject;
Debug.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;
holder.SetObjectValue(((IObjectReference)(holder.ObjectValue)).GetRealObject(_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);
return false;
}
if (depthCount++ == MaxReferenceDepth)
{
throw new SerializationException(SR.Serialization_TooManyReferences);
}
} while ((holder.ObjectValue is IObjectReference) && (tempObject != holder.ObjectValue));
}
catch (NullReferenceException)
{
return false;
}
holder.IsIncompleteObjectReference = false;
DoNewlyRegisteredObjectFixups(holder);
return true;
}