/// <summary> /// Secondary entry point for all object representations. Called primarily by /// <see cref="Prepare(object,bool)"/>, but also recursively when preparing interactive /// reflected objects, etc. to prepare child member values. /// </summary> /// <param name="representations">The representations already produced for this object.</param> /// <param name="depth">The current object graph depth.</param> /// <param name="obj">The current object to represent.</param> internal void Prepare(RepresentedObject representations, int depth, object obj) { if (obj == null) { return; } MainThread.Ensure(); var normalizedObj = Normalize(obj); representations.Add(normalizedObj); if (normalizedObj == null) { representations.Add(ToJson(obj)); } else { representations.Add(ToJson(normalizedObj)); } var skipInteractive = false; var interactiveObj = obj; // It is not safe to provide Representation objects to providers // which can cause a stack overflow in Normalize if the provider // decides to directly pack the provied Representation object in // another Representation object for whatever reason. if (obj is Representation) { obj = ((Representation)obj).Value; } foreach (var provider in providers) { try { foreach (var representation in provider.ProvideRepresentations(obj)) { representations.Add(Normalize(representation)); skipInteractive |= representation is InteractiveObject.GetMemberValueError; } } catch (Exception e) { Log.Error(TAG, $"provider {provider}.ProvideRepresentation", e); } } if (skipInteractive) { return; } foreach (var interactiveObject in PrepareInteractiveObjects(depth, interactiveObj)) { interactiveObject.Handle = ObjectCache.Shared.GetHandle(interactiveObject); interactiveObject.Initialize(); representations.Add(interactiveObject); } }
void SafeReadMembers() { var propertyNames = new HashSet <string> (); var members = new List <Tuple <RepresentedMemberInfo, object> > (); for (var type = RepresentedType; type != null; type = type.BaseType) { foreach (var memberItem in type.ProxyableMembers) { var pi = memberItem.Value.ResolvedMemberInfo as PropertyInfo; if (pi != null) { if (propertyNames.Contains(pi.Name)) { continue; } propertyNames.Add(pi.Name); } object value; try { if (memberFilter != null && !memberFilter(memberItem.Value, representedObject)) { value = new GetMemberValueError(); } else { value = memberItem.Value.GetValue(representedObject); } } catch (TargetInvocationException e) { value = new GetMemberValueError(e.InnerException); } catch (Exception e) { value = new GetMemberValueError(e); } var preparedValue = new RepresentedObject(value?.GetType()); ItemPreparer(preparedValue, Depth + 1, value); if (preparedValue.Count == 0) { preparedValue = null; } members.Add(Tuple.Create(memberItem.Value, (object)preparedValue)); } } members.Sort((x, y) => string.Compare(x.Item1.Name, y.Item1.Name)); Members = new RepresentedMemberInfo [members.Count]; Values = new object [members.Count]; for (int i = 0; i < members.Count; i++) { Members [i] = members [i].Item1; Values [i] = members [i].Item2; } }
protected override IInteractiveObject Interact(bool isUserInteraction, object message) { if (!isUserInteraction && Depth > 0) { return(this); } if (slice == null) { slice = new object [defaultSliceSize]; } int i = 0; while (i < slice.Length) { // In case of error, default to true so we can show "cannot evaluate" var enumerated = true; object current = null; try { enumerated = enumerator.MoveNext(); if (enumerated) { current = enumerator.Current; } } catch (Exception e) { Log.Error(TAG, e); current = new InteractiveObject.GetMemberValueError(e); } if (!enumerated) { IsLastSlice = true; break; } var result = new RepresentedObject(current?.GetType()); ItemPreparer(result, Depth + 1, current); if (result.Count == 0) { result = null; } slice [i++] = result; } if (i < slice.Length) { Array.Resize(ref slice, i); } return(this); }
protected override void ReadMembers() { Members = new RepresentedMemberInfo [values.Count]; Values = new object [values.Count]; for (int i = 0; i < values.Count; i++) { var entry = values [i]; var value = new RepresentedObject(entry.Item2?.GetType()); ItemPreparer(value, Depth + 1, entry.Item2); if (value.Count == 0) { value = null; } Members [i] = entry.Item1; Values [i] = value; } }
/// <summary> /// Prepare serializable representations for an arbitrary object. /// </summary> public RepresentedObject Prepare(object obj, bool allowISerializableObject = true) { if (obj == null) { return(null); } MainThread.Ensure(); currentPreparePassAllowsISerializableObject = allowISerializableObject; var representations = new RepresentedObject(obj.GetType()); Prepare(representations, 0, obj); if (representations.Count == 0) { return(null); } return(representations); }