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;
66 string converterTypeName = null;
67 Type realType = toType;
69 if (true == realType.IsGenericType && typeof(Nullable<>) == realType.GetGenericTypeDefinition())
71 realType = realType.GetGenericArguments()[0];
74 converterTypeName = realType.CustomAttributes.GetTypeConverterTypeName();
75 if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
76 converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
78 if (converterTypeName == null)
80 converterTypeName = toType.FullName + "TypeConverter";
83 var convertertype = Type.GetType(converterTypeName);
85 if (null == convertertype)
91 return Activator.CreateInstance(convertertype);
95 return ConvertTo(value, toType, getConverter, serviceProvider);
98 static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
100 var converterAttribute =
101 attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
102 if (converterAttribute == null)
104 if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof(string))
105 return (string)converterAttribute.ConstructorArguments[0].Value;
106 if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof(Type))
107 return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
111 //Don't change the name or the signature of this, it's used by XamlC
112 public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
114 if (convertertype == null)
115 return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
116 Func<object> getConverter = () => Activator.CreateInstance(convertertype);
118 return value.ConvertTo(toType, getConverter, serviceProvider);
121 private delegate void ParseValueFunc(string s, IFormatProvider provider);
123 static private Dictionary<Type, ParseValueFunc> typeToParseValueFunc = null;
125 static private void BuildParseValueFunc()
127 if (null == typeToParseValueFunc)
129 typeToParseValueFunc = new Dictionary<Type, ParseValueFunc>();
134 internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
135 IServiceProvider serviceProvider)
140 var str = value as string;
143 //If there's a [TypeConverter], use it
144 object converter = getConverter?.Invoke();
145 if (null != converter)
147 var xfTypeConverter = converter as TypeConverter;
148 var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
149 if (xfExtendedTypeConverter != null)
150 return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
151 if (xfTypeConverter != null)
152 return value = xfTypeConverter.ConvertFromInvariantString(str);
153 var converterType = converter?.GetType();
154 if (converterType != null)
156 var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
157 new[] { typeof(string) });
158 if (convertFromStringInvariant != null)
159 return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
163 var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
165 //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
166 if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>))
167 toType = Nullable.GetUnderlyingType(toType);
169 //Obvious Built-in conversions
170 if (toType.GetTypeInfo().IsEnum)
171 return Enum.Parse(toType, str, ignoreCase);
173 if (toType == typeof(SByte))
174 return SByte.Parse(str, CultureInfo.InvariantCulture);
175 if (toType == typeof(Int16))
176 return Int16.Parse(str, CultureInfo.InvariantCulture);
177 if (toType == typeof(Int32))
178 return Int32.Parse(str, CultureInfo.InvariantCulture);
179 if (toType == typeof(Int64))
180 return Int64.Parse(str, CultureInfo.InvariantCulture);
181 if (toType == typeof(Byte))
182 return Byte.Parse(str, CultureInfo.InvariantCulture);
183 if (toType == typeof(UInt16))
184 return UInt16.Parse(str, CultureInfo.InvariantCulture);
185 if (toType == typeof(UInt32))
186 return UInt32.Parse(str, CultureInfo.InvariantCulture);
187 if (toType == typeof(UInt64))
188 return UInt64.Parse(str, CultureInfo.InvariantCulture);
189 if (toType == typeof(Single))
190 return Single.Parse(str, CultureInfo.InvariantCulture);
191 if (toType == typeof(Double))
192 return Double.Parse(str, CultureInfo.InvariantCulture);
193 if (toType == typeof(Boolean))
194 return Boolean.Parse(str);
195 if (toType == typeof(TimeSpan))
196 return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
197 if (toType == typeof(DateTime))
198 return DateTime.Parse(str, CultureInfo.InvariantCulture);
199 if (toType == typeof(Char))
202 Char.TryParse(str, out c);
205 if (toType == typeof(String) && str.StartsWith("{}", StringComparison.Ordinal))
206 return str.Substring(2);
207 if (toType == typeof(String))
209 if (toType == typeof(Decimal))
210 return Decimal.Parse(str, CultureInfo.InvariantCulture);
213 //if the value is not assignable and there's an implicit conversion, convert
214 if (value != null && !toType.IsAssignableFrom(value.GetType()))
216 var opImplicit = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
217 ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);
219 if (opImplicit != null)
221 value = opImplicit.Invoke(null, new[] { value });
229 internal static MethodInfo GetImplicitConversionOperator(this Type onType, Type fromType, Type toType)
232 var mi = onType.GetRuntimeMethod("op_Implicit", new[] { fromType });
234 var bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
235 var mi = onType.GetMethod("op_Implicit", bindingFlags, null, new[] { fromType }, null);
237 if (mi == null) return null;
238 if (!mi.IsSpecialName) return null;
239 if (!mi.IsPublic) return null;
240 if (!mi.IsStatic) return null;
241 if (!toType.IsAssignableFrom(mi.ReturnType)) return null;