static class TypeConversionExtensions
{
internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
- IServiceProvider serviceProvider)
+ IServiceProvider serviceProvider, out Exception exception)
{
Func<TypeConverter> getConverter = () =>
{
return (TypeConverter)Activator.CreateInstance(convertertype);
};
- return ConvertTo(value, toType, getConverter, serviceProvider);
+ return ConvertTo(value, toType, getConverter, serviceProvider, out exception);
}
internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
- IServiceProvider serviceProvider)
+ IServiceProvider serviceProvider, out Exception exception)
{
Func<object> getConverter = () =>
{
return Activator.CreateInstance(convertertype);
};
- return ConvertTo(value, toType, getConverter, serviceProvider);
+ return ConvertTo(value, toType, getConverter, serviceProvider, out exception);
}
static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
//Don't change the name or the signature of this, it's used by XamlC
public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
{
- if (convertertype == null)
- return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
+ Exception exception = null;
+ object ret = null;
+ if (convertertype == null) {
+ ret = value.ConvertTo(toType, (Func<object>)null, serviceProvider, out exception);
+ if (exception != null)
+ throw exception;
+ return ret;
+ }
Func<object> getConverter = () => Activator.CreateInstance(convertertype);
- ;
- return value.ConvertTo(toType, getConverter, serviceProvider);
+ ret = value.ConvertTo(toType, getConverter, serviceProvider, out exception);
+ if (exception != null)
+ throw exception;
+ return ret;
}
internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
- IServiceProvider serviceProvider)
+ IServiceProvider serviceProvider, out Exception exception)
{
+ exception = null;
if (value == null)
return null;
- var str = value as string;
- if (str != null)
- {
+ if (value is string str) {
//If there's a [TypeConverter], use it
- object converter = getConverter?.Invoke();
- var xfTypeConverter = converter as TypeConverter;
- var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
- if (xfExtendedTypeConverter != null)
- return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
- if (xfTypeConverter != null) {
- try {
- return value = xfTypeConverter.ConvertFromInvariantString(str);
- }
- catch (Exception e) {
- throw new XamlParseException("Type conversion failed", serviceProvider, e);
- }
+ object converter;
+ try { //minforetriver can fail
+ converter = getConverter?.Invoke();
+ }
+ catch (Exception e) {
+ exception = e;
+ return null;
+ }
+ try {
+ if (converter is IExtendedTypeConverter xfExtendedTypeConverter)
+ return xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
+ if (converter is TypeConverter xfTypeConverter)
+ return xfTypeConverter.ConvertFromInvariantString(str);
+ }
+ catch (Exception e)
+ {
+ exception = e as XamlParseException ?? new XamlParseException("Type converter failed", serviceProvider, e);
+ return null;
}
var converterType = converter?.GetType();
if (converterType != null)
var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
new[] { typeof (string) });
if (convertFromStringInvariant != null)
- return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
+ try {
+ return convertFromStringInvariant.Invoke(converter, new object[] { str });
+ }
+ catch (Exception e) {
+ exception = new XamlParseException("Type conversion failed", serviceProvider, e);
+ return null;
+ }
}
var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
toType = Nullable.GetUnderlyingType(toType);
//Obvious Built-in conversions
- if (toType.GetTypeInfo().IsEnum)
- return Enum.Parse(toType, str, ignoreCase);
- if (toType == typeof(SByte))
- return SByte.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(Int16))
- return Int16.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(Int32))
- return Int32.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(Int64))
- return Int64.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(Byte))
- return Byte.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(UInt16))
- return UInt16.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(UInt32))
- return UInt32.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(UInt64))
- return UInt64.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (Single))
- return Single.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (Double))
- return Double.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (Boolean))
- return Boolean.Parse(str);
- if (toType == typeof (TimeSpan))
- return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (DateTime))
- return DateTime.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof(Char)) {
- char c = '\0';
- Char.TryParse(str, out c);
- return c;
+ try {
+ if (toType.GetTypeInfo().IsEnum)
+ return Enum.Parse(toType, str, ignoreCase);
+ if (toType == typeof(SByte))
+ return SByte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int16))
+ return Int16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int32))
+ return Int32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int64))
+ return Int64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Byte))
+ return Byte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt16))
+ return UInt16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt32))
+ return UInt32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt64))
+ return UInt64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Single))
+ return Single.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Double))
+ return Double.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Boolean))
+ return Boolean.Parse(str);
+ if (toType == typeof(TimeSpan))
+ return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(DateTime))
+ return DateTime.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Char)) {
+ Char.TryParse(str, out var c);
+ return c;
+ }
+ if (toType == typeof(String) && str.StartsWith("{}", StringComparison.Ordinal))
+ return str.Substring(2);
+ if (toType == typeof(String))
+ return value;
+ if (toType == typeof(Decimal))
+ return Decimal.Parse(str, CultureInfo.InvariantCulture);
+ }
+ catch (FormatException fe) {
+ exception = fe;
+ return null;
}
- if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
- return str.Substring(2);
- if (toType == typeof (String))
- return value;
- if (toType == typeof(Decimal))
- return Decimal.Parse(str, CultureInfo.InvariantCulture);
}
//if the value is not assignable and there's an implicit conversion, convert
exception = null;
var elementType = element.GetType();
- var binding = value.ConvertTo(typeof(BindingBase),pinfoRetriever:null,serviceProvider:null) as BindingBase;
+ var binding = value.ConvertTo(typeof(BindingBase),pinfoRetriever:null,serviceProvider:null, exception:out exception) as BindingBase;
+ if (exception != null)
+ return false;
var bindable = element as BindableObject;
var nativeBindingService = DependencyService.Get<INativeBindingService>();
throw new XamlParseException($"Multiple properties with name '{property.DeclaringType}.{property.PropertyName}' found.", lineInfo, innerException: e);
}
};
- var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);
+ var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider, out exception);
+ if (exception != null)
+ return false;
if (bindable != null) {
//SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding
}
// This might be a collection; see if we can add to it
- return TryAddValue(bindable, property, value, serviceProvider);
+ return TryAddValue(bindable, property, value, serviceProvider, out exception);
}
if (nativeBindingService != null && nativeBindingService.TrySetValue(element, property, convertedValue))
if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = propertyInfo;
- object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider);
- if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue))
+ object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider, out exception);
+ if (exception != null || (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue)))
return false;
try {
if (serviceProvider != null)
((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
- addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
- return true;
+ addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func<TypeConverter>)null, serviceProvider, out exception) });
+ return exception == null;
}
static bool TryAddToResourceDictionary(ResourceDictionary resourceDictionary, object value, string xKey, IXmlLineInfo lineInfo, out Exception exception)
};
}
- static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider)
+ static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider, out Exception exception)
{
- if(property?.ReturnTypeInfo?.GenericTypeArguments == null){
+ exception = null;
+
+ if (property?.ReturnTypeInfo?.GenericTypeArguments == null)
return false;
- }
- if(property.ReturnType == null){
+ if (property.ReturnType == null)
return false;
- }
- if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 ||
- !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value))
+ if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 || !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value))
return false;
// This might be a collection we can add to; see if we can find an Add method
- var addMethod = GetAllRuntimeMethods(property.ReturnType)
- .FirstOrDefault(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
+ var addMethod = GetAllRuntimeMethods(property.ReturnType).FirstOrDefault(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
if (addMethod == null)
return false;
var collection = bindable.GetValue(property);
// And add the new value to it
- addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
- return true;
+ addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider, out exception) });
+ return exception == null;
}
static IEnumerable<MethodInfo> GetAllRuntimeMethods(Type type)