// ----------------------------------------------------------------------- // // Copyright 2015 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Utilities { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; /// /// Provides utilities for working with types at runtime. /// internal static class TypeUtilities { private static readonly Dictionary> Conversions = new Dictionary>() { { typeof(decimal), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } }, { typeof(double), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, { typeof(float), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, { typeof(ulong), new List { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } }, { typeof(long), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } }, { typeof(uint), new List { typeof(byte), typeof(ushort), typeof(char) } }, { typeof(int), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } }, { typeof(ushort), new List { typeof(byte), typeof(char) } }, { typeof(short), new List { typeof(byte) } } }; /// /// Try to cast a value to a type, using implicit conversions if possible. /// /// The type to cast to. /// The value to cast. /// If sucessful, contains the cast value. /// True if the cast was sucessful, otherwise false. public static bool TryCast(Type to, object value, out object result) { Contract.Requires(to != null); if (value == null) { var t = to.GetTypeInfo(); result = null; return !t.IsValueType || (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>))); } var from = value.GetType(); if (value == PerspexProperty.UnsetValue) { result = value; return true; } else if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo())) { result = value; return true; } else if (Conversions.ContainsKey(to) && Conversions[to].Contains(from)) { result = Convert.ChangeType(value, to); return true; } else { var cast = from.GetTypeInfo() .GetDeclaredMethods("op_Implicit") .FirstOrDefault(m => m.ReturnType == to); if (cast != null) { result = cast.Invoke(null, new[] { value }); return true; } } result = null; return false; } } }