2 // TypeConversionExtensions.cs
5 // Stephane Delcroix <stephane@mi8.be>
7 // Copyright (c) 2013 Mobile Inception
8 // Copyright (c) 2014 Xamarin, Inc.
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 using System.Collections.Generic;
30 using System.Globalization;
32 using System.Reflection;
33 // using Tizen.NUI.Binding.Internals;
34 using Tizen.NUI.Xaml.Internals;
35 using Tizen.NUI.Binding;
37 namespace Tizen.NUI.Xaml
39 internal static class TypeConversionExtensions
41 internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
42 IServiceProvider serviceProvider)
44 Func<TypeConverter> getConverter = () =>
47 if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
50 var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
51 if (converterTypeName == null)
53 var convertertype = Type.GetType(converterTypeName);
54 return (TypeConverter)Activator.CreateInstance(convertertype);
57 return ConvertTo(value, toType, getConverter, serviceProvider);
60 internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
61 IServiceProvider serviceProvider)
63 Func<object> getConverter = () =>
65 MemberInfo memberInfo;
67 var converterTypeName = toType.GetTypeInfo().CustomAttributes.GetTypeConverterTypeName();
68 if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
69 converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
70 if (converterTypeName == null)
73 var convertertype = Type.GetType(converterTypeName);
74 return Activator.CreateInstance(convertertype);
77 return ConvertTo(value, toType, getConverter, serviceProvider);
80 static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
82 var converterAttribute =
83 attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
84 if (converterAttribute == null)
86 if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (string))
87 return (string)converterAttribute.ConstructorArguments[0].Value;
88 if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (Type))
89 return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
93 //Don't change the name or the signature of this, it's used by XamlC
94 public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
96 if (convertertype == null)
97 return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
98 Func<object> getConverter = () => Activator.CreateInstance(convertertype);
100 return value.ConvertTo(toType, getConverter, serviceProvider);
103 private delegate void ParseValueFunc(string s, IFormatProvider provider);
105 static private Dictionary<Type, ParseValueFunc> typeToParseValueFunc = null;
107 static private void BuildParseValueFunc()
109 if (null == typeToParseValueFunc)
111 typeToParseValueFunc = new Dictionary<Type, ParseValueFunc>();
116 internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
117 IServiceProvider serviceProvider)
122 var str = value as string;
125 //If there's a [TypeConverter], use it
126 object converter = getConverter?.Invoke();
127 if (null != converter)
129 var xfTypeConverter = converter as TypeConverter;
130 var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
131 if (xfExtendedTypeConverter != null)
132 return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
133 if (xfTypeConverter != null)
134 return value = xfTypeConverter.ConvertFromInvariantString(str);
135 var converterType = converter?.GetType();
136 if (converterType != null)
138 var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
139 new[] { typeof(string) });
140 if (convertFromStringInvariant != null)
141 return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
145 var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
147 //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
148 if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof (Nullable<>))
149 toType = Nullable.GetUnderlyingType(toType);
151 //Obvious Built-in conversions
152 if (toType.GetTypeInfo().IsEnum)
153 return Enum.Parse(toType, str, ignoreCase);
155 if (toType == typeof(SByte))
156 return SByte.Parse(str, CultureInfo.InvariantCulture);
157 if (toType == typeof(Int16))
158 return Int16.Parse(str, CultureInfo.InvariantCulture);
159 if (toType == typeof(Int32))
160 return Int32.Parse(str, CultureInfo.InvariantCulture);
161 if (toType == typeof(Int64))
162 return Int64.Parse(str, CultureInfo.InvariantCulture);
163 if (toType == typeof(Byte))
164 return Byte.Parse(str, CultureInfo.InvariantCulture);
165 if (toType == typeof(UInt16))
166 return UInt16.Parse(str, CultureInfo.InvariantCulture);
167 if (toType == typeof(UInt32))
168 return UInt32.Parse(str, CultureInfo.InvariantCulture);
169 if (toType == typeof(UInt64))
170 return UInt64.Parse(str, CultureInfo.InvariantCulture);
171 if (toType == typeof (Single))
172 return Single.Parse(str, CultureInfo.InvariantCulture);
173 if (toType == typeof (Double))
174 return Double.Parse(str, CultureInfo.InvariantCulture);
175 if (toType == typeof (Boolean))
176 return Boolean.Parse(str);
177 if (toType == typeof (TimeSpan))
178 return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
179 if (toType == typeof (DateTime))
180 return DateTime.Parse(str, CultureInfo.InvariantCulture);
181 if (toType == typeof(Char)) {
183 Char.TryParse(str, out c);
186 if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
187 return str.Substring(2);
188 if (toType == typeof (String))
190 if (toType == typeof(Decimal))
191 return Decimal.Parse(str, CultureInfo.InvariantCulture);
194 //if the value is not assignable and there's an implicit conversion, convert
195 if (value != null && !toType.IsAssignableFrom(value.GetType())) {
196 var opImplicit = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
197 ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);
199 if (opImplicit != null) {
200 value = opImplicit.Invoke(null, new[] { value });
208 internal static MethodInfo GetImplicitConversionOperator(this Type onType, Type fromType, Type toType)
211 var mi = onType.GetRuntimeMethod("op_Implicit", new[] { fromType });
213 var bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
214 var mi = onType.GetMethod("op_Implicit", bindingFlags, null, new[] { fromType }, null);
216 if (mi == null) return null;
217 if (!mi.IsSpecialName) return null;
218 if (!mi.IsPublic) return null;
219 if (!mi.IsStatic) return null;
220 if (!toType.IsAssignableFrom(mi.ReturnType)) return null;