2 * Copyright(c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 // TypeConversionExtensions.cs
21 // Stephane Delcroix <stephane@mi8.be>
23 // Copyright (c) 2013 Mobile Inception
24 // Copyright (c) 2014 Xamarin, Inc.
26 // Permission is hereby granted, free of charge, to any person obtaining a copy
27 // of this software and associated documentation files (the "Software"), to deal
28 // in the Software without restriction, including without limitation the rights
29 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 // copies of the Software, and to permit persons to whom the Software is
31 // furnished to do so, subject to the following conditions:
33 // The above copyright notice and this permission notice shall be included in
34 // all copies or substantial portions of the Software.
36 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45 using System.Collections.Generic;
46 using System.Globalization;
48 using System.Reflection;
49 // using Tizen.NUI.Binding.Internals;
50 using Tizen.NUI.Xaml.Internals;
51 using Tizen.NUI.Binding;
53 namespace Tizen.NUI.Xaml
55 internal static class TypeConversionExtensions
57 internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
58 IServiceProvider serviceProvider)
60 Func<TypeConverter> getConverter = () =>
63 if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
66 var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
67 if (converterTypeName == null)
69 var convertertype = Type.GetType(converterTypeName);
70 return (TypeConverter)Activator.CreateInstance(convertertype);
73 return ConvertTo(value, toType, getConverter, serviceProvider);
76 internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
77 IServiceProvider serviceProvider)
79 Func<object> getConverter = () =>
81 MemberInfo memberInfo;
82 string converterTypeName = null;
83 Type realType = toType;
85 if (true == realType.IsGenericType && typeof(Nullable<>) == realType.GetGenericTypeDefinition())
87 realType = realType.GetGenericArguments()[0];
90 converterTypeName = realType.CustomAttributes.GetTypeConverterTypeName();
91 if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
92 converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
94 if (converterTypeName == null)
96 converterTypeName = toType.FullName + "TypeConverter";
99 var convertertype = Type.GetType(converterTypeName);
101 if (null == convertertype)
107 return Activator.CreateInstance(convertertype);
111 return ConvertTo(value, toType, getConverter, serviceProvider);
114 static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
116 var converterAttribute =
117 attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
118 if (converterAttribute == null)
120 if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof(string))
121 return (string)converterAttribute.ConstructorArguments[0].Value;
122 if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof(Type))
123 return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
127 //Don't change the name or the signature of this, it's used by XamlC
128 public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
130 if (convertertype == null)
131 return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
132 Func<object> getConverter = () => Activator.CreateInstance(convertertype);
134 return value.ConvertTo(toType, getConverter, serviceProvider);
137 private delegate void ParseValueFunc(string s, IFormatProvider provider);
139 static private Dictionary<Type, ParseValueFunc> typeToParseValueFunc = null;
141 static private void BuildParseValueFunc()
143 if (null == typeToParseValueFunc)
145 typeToParseValueFunc = new Dictionary<Type, ParseValueFunc>();
150 internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
151 IServiceProvider serviceProvider)
156 var str = value as string;
159 //If there's a [TypeConverter], use it
160 object converter = getConverter?.Invoke();
161 if (null != converter)
163 var xfTypeConverter = converter as TypeConverter;
164 var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
165 if (xfExtendedTypeConverter != null)
166 return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
167 if (xfTypeConverter != null)
168 return value = xfTypeConverter.ConvertFromInvariantString(str);
169 var converterType = converter?.GetType();
170 if (converterType != null)
172 var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
173 new[] { typeof(string) });
174 if (convertFromStringInvariant != null)
175 return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
179 var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
181 //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
182 if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>))
183 toType = Nullable.GetUnderlyingType(toType);
185 //Obvious Built-in conversions
186 if (toType.GetTypeInfo().IsEnum)
187 return Enum.Parse(toType, str, ignoreCase);
189 if (toType == typeof(SByte))
190 return SByte.Parse(str, CultureInfo.InvariantCulture);
191 if (toType == typeof(Int16))
192 return Int16.Parse(str, CultureInfo.InvariantCulture);
193 if (toType == typeof(Int32))
194 return Int32.Parse(str, CultureInfo.InvariantCulture);
195 if (toType == typeof(Int64))
196 return Int64.Parse(str, CultureInfo.InvariantCulture);
197 if (toType == typeof(Byte))
198 return Byte.Parse(str, CultureInfo.InvariantCulture);
199 if (toType == typeof(UInt16))
200 return UInt16.Parse(str, CultureInfo.InvariantCulture);
201 if (toType == typeof(UInt32))
202 return UInt32.Parse(str, CultureInfo.InvariantCulture);
203 if (toType == typeof(UInt64))
204 return UInt64.Parse(str, CultureInfo.InvariantCulture);
205 if (toType == typeof(Single))
206 return Single.Parse(str, CultureInfo.InvariantCulture);
207 if (toType == typeof(Double))
208 return Double.Parse(str, CultureInfo.InvariantCulture);
209 if (toType == typeof(Boolean))
210 return Boolean.Parse(str);
211 if (toType == typeof(TimeSpan))
212 return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
213 if (toType == typeof(DateTime))
214 return DateTime.Parse(str, CultureInfo.InvariantCulture);
215 if (toType == typeof(Char))
218 _ = Char.TryParse(str, out c);
221 if (toType == typeof(String) && str.StartsWith("{}", StringComparison.Ordinal))
222 return str.Substring(2);
223 if (toType == typeof(String))
225 if (toType == typeof(Decimal))
226 return Decimal.Parse(str, CultureInfo.InvariantCulture);
229 //if the value is not assignable and there's an implicit conversion, convert
230 if (value != null && !toType.IsAssignableFrom(value.GetType()))
232 var opImplicit = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
233 ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);
235 if (opImplicit != null)
237 value = opImplicit.Invoke(null, new[] { value });
245 internal static MethodInfo GetImplicitConversionOperator(this Type onType, Type fromType, Type toType)
248 var mi = onType.GetRuntimeMethod("op_Implicit", new[] { fromType });
250 var bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
251 var mi = onType.GetMethod("op_Implicit", bindingFlags, null, new[] { fromType }, null);
253 if (mi == null) return null;
254 if (!mi.IsSpecialName) return null;
255 if (!mi.IsPublic) return null;
256 if (!mi.IsStatic) return null;
257 if (!toType.IsAssignableFrom(mi.ReturnType)) return null;