// Note that this returns XamlMember which might not actually appear in XamlObjectReader. For example, XamlLanguage.Items won't be returned when there is no item in the collection. public static IEnumerable <XamlMember> GetAllObjectReaderMembersByType(this XamlType type, IValueSerializerContext vsctx) { if (type.HasPositionalParameters(vsctx)) { yield return(XamlLanguage.PositionalParameters); yield break; } // Note that if the XamlType has the default constructor, we don't need "Arguments". IEnumerable <XamlMember> args = type.ConstructionRequiresArguments ? type.GetSortedConstructorArguments() : null; if (args != null && args.Any()) { yield return(XamlLanguage.Arguments); } if (type.IsContentValue(vsctx)) { yield return(XamlLanguage.Initialization); yield break; } if (type.IsDictionary) { yield return(XamlLanguage.Items); yield break; } foreach (var m in type.GetAllMembers()) { // do not read constructor arguments twice (they are written inside Arguments). if (args != null && args.Contains(m)) { continue; } // do not return non-public members (of non-collection/xdata). Not sure why .NET filters out them though. if (!m.IsReadPublic) { continue; } if (!m.IsWritePublic && !m.Type.IsXData && !m.Type.IsArray && !m.Type.IsCollection && !m.Type.IsDictionary) { continue; } yield return(m); } if (type.IsCollection) { yield return(XamlLanguage.Items); } }
// It expects that it is not invoked when there is no value to // assign. // When it is passed null, then it returns a default instance. // For example, passing null as Int32 results in 0. // But do not immediately try to instantiate with the type, since the type might be abstract. object GetCorrectlyTypedValue(XamlMember xm, XamlType xt, object value, bool fallbackToString = false) { try { if (value == null) { if (xt.IsContentValue(service_provider)) // it is for collection/dictionary key and item { return(null); } else { return(xt.IsNullable ? null : xt.Invoker.CreateInstance(new object[0])); } } if (ReferenceEquals(xt, null)) { return(value); } // Not sure if this is really required though... var vt = sctx.GetXamlType(value.GetType()); if (vt.CanAssignTo(xt)) { return(value); } // FIXME: this could be generalized by some means, but I cannot find any. if (xt.UnderlyingType == typeof(XamlType) && value is string) { value = ResolveTypeFromName((string)value); } // FIXME: this could be generalized by some means, but I cannot find any. if (xt.UnderlyingType == typeof(Type)) { value = new TypeExtension((string)value).ProvideValue(service_provider); } if (ReferenceEquals(xt, XamlLanguage.Type) && value is string) { value = new TypeExtension((string)value); } if (IsAllowedType(xt, value)) { return(value); } var xtc = xm?.TypeConverter ?? xt.TypeConverter; if (xtc != null && value != null) { var tc = xtc.ConverterInstance; if (tc != null && tc.CanConvertFrom(service_provider, value.GetType())) { value = tc.ConvertFrom(service_provider, CultureInfo.InvariantCulture, value); } return(value); } } catch (Exception ex) { // For + ex.Message, the runtime should print InnerException message like .NET does. throw WithLineInfo(new XamlObjectWriterException( String.Format("Could not convert object \'{0}' (of type {1}) to {2}: ", value, value != null ? (object)value.GetType() : "(null)", xt) + ex.Message, ex)); } return(fallbackToString ? value : throw WithLineInfo(new XamlObjectWriterException( String.Format("Value '{0}' (of type {1}) is not of or convertible to type {2} (member {3})", value, value != null ? (object)value.GetType() : "(null)", xt, xm), null))); }