maui-linux/Xamarin.Forms.Xaml/TypeConversionExtensions.cs

214 строки
8.1 KiB
C#
Исходник Обычный вид История

2016-03-22 23:02:25 +03:00
//
// TypeConversionExtensions.cs
2016-03-22 23:02:25 +03:00
//
// Author:
// Stephane Delcroix <stephane@mi8.be>
//
// Copyright (c) 2013 Mobile Inception
// Copyright (c) 2014 Xamarin, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
namespace Xamarin.Forms.Xaml
{
internal static class TypeConversionExtensions
{
internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
IServiceProvider serviceProvider)
{
Func<TypeConverter> getConverter = () =>
{
ParameterInfo pInfo;
if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
return null;
var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
if (converterTypeName == null)
return null;
var convertertype = Type.GetType(converterTypeName);
return (TypeConverter)Activator.CreateInstance(convertertype);
};
return ConvertTo(value, toType, getConverter, serviceProvider);
}
internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
IServiceProvider serviceProvider)
{
Func<object> getConverter = () =>
{
MemberInfo memberInfo;
var converterTypeName = toType.GetTypeInfo().CustomAttributes.GetTypeConverterTypeName();
if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
if (converterTypeName == null)
return null;
var convertertype = Type.GetType(converterTypeName);
return Activator.CreateInstance(convertertype);
};
return ConvertTo(value, toType, getConverter, serviceProvider);
}
static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
{
var converterAttribute =
attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
if (converterAttribute == null)
return null;
if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (string))
return (string)converterAttribute.ConstructorArguments[0].Value;
if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (Type))
return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
return null;
}
//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);
Func<object> getConverter = () => Activator.CreateInstance(convertertype);
;
return value.ConvertTo(toType, getConverter, serviceProvider);
}
internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
IServiceProvider serviceProvider)
{
if (value == null)
return null;
var str = value as string;
if (str != null)
{
//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)
return value = xfTypeConverter.ConvertFromInvariantString(str);
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 });
}
//If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof (Nullable<>))
toType = Nullable.GetUnderlyingType(toType);
//Obvious Built-in conversions
if (toType.GetTypeInfo().IsEnum)
return Enum.Parse(toType, str);
if (toType == typeof(SByte))
return SByte.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof(Int16))
return Int16.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof(Int32))
2016-03-22 23:02:25 +03:00
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))
2016-03-22 23:02:25 +03:00
return Single.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof (Double))
2016-03-22 23:02:25 +03:00
return Double.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof (Boolean))
2016-03-22 23:02:25 +03:00
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;
}
if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
2016-03-22 23:02:25 +03:00
return str.Substring(2);
if (toType == typeof (String))
2016-03-22 23:02:25 +03:00
return value;
if (toType == typeof(Decimal))
return Decimal.Parse(str, CultureInfo.InvariantCulture);
2016-03-22 23:02:25 +03:00
}
//if there's an implicit conversion, convert
if (value != null) {
MethodInfo opImplicit = null;
foreach (var mi in value.GetType().GetRuntimeMethods()) {
if (!mi.IsSpecialName) continue;
if (mi.Name != "op_Implicit") continue;
if (!mi.IsPublic) continue;
if (mi.ReturnType != toType) continue;
var parameters = mi.GetParameters();
if (parameters.Length != 1) continue;
if (parameters[0].ParameterType != value.GetType()) continue;
opImplicit = mi;
break;
}
if (opImplicit == null) {
foreach (var mi in toType.GetRuntimeMethods()) {
if (!mi.IsSpecialName) continue;
if (mi.Name != "op_Implicit") continue;
if (!mi.IsPublic) continue;
if (mi.ReturnType != toType) continue;
var parameters = mi.GetParameters();
if (parameters.Length != 1) continue;
if (parameters[0].ParameterType != value.GetType()) continue;
opImplicit = mi;
break;
}
}
if (opImplicit != null) {
value = opImplicit.Invoke(null, new[] { value });
return value;
}
2016-03-22 23:02:25 +03:00
}
var nativeValueConverterService = DependencyService.Get<INativeValueConverterService>();
object nativeValue = null;
if (nativeValueConverterService != null && nativeValueConverterService.ConvertTo(value, toType, out nativeValue))
return nativeValue;
2016-03-22 23:02:25 +03:00
return value;
}
}
}