9 changed files with 171 additions and 65 deletions
@ -0,0 +1,83 @@ |
|||||
|
// -----------------------------------------------------------------------
|
||||
|
// <copyright file="TypeUtilities.cs" company="Steven Kirk">
|
||||
|
// Copyright 2015 MIT Licence. See licence.md for more information.
|
||||
|
// </copyright>
|
||||
|
// -----------------------------------------------------------------------
|
||||
|
|
||||
|
namespace Perspex.Utilities |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides utilities for working with types at runtime.
|
||||
|
/// </summary>
|
||||
|
internal static class TypeUtilities |
||||
|
{ |
||||
|
private static readonly Dictionary<Type, List<Type>> Conversions = new Dictionary<Type, List<Type>>() { |
||||
|
{ typeof(decimal), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } }, |
||||
|
{ typeof(double), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, |
||||
|
{ typeof(float), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, |
||||
|
{ typeof(ulong), new List<Type> { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } }, |
||||
|
{ typeof(long), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } }, |
||||
|
{ typeof(uint), new List<Type> { typeof(byte), typeof(ushort), typeof(char) } }, |
||||
|
{ typeof(int), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } }, |
||||
|
{ typeof(ushort), new List<Type> { typeof(byte), typeof(char) } }, |
||||
|
{ typeof(short), new List<Type> { typeof(byte) } } |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Try to cast a value to a type, using implicit conversions if possible.
|
||||
|
/// </summary>
|
||||
|
/// <param name="to">The type to cast to.</param>
|
||||
|
/// <param name="value">The value to cast.</param>
|
||||
|
/// <param name="result">If sucessful, contains the cast value.</param>
|
||||
|
/// <returns>True if the cast was sucessful, otherwise false.</returns>
|
||||
|
public static bool TryCast(Type to, object value, out object result) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
|
// attributes that are applied to this project.
|
||||
|
// Project-level suppressions either have no target or are given
|
||||
|
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
|
||||
|
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( |
||||
|
"StyleCop.CSharp.DocumentationRules", |
||||
|
"SA1600:Elements must be documented", |
||||
|
Justification = "Tests should be self-documenting")] |
||||
|
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( |
||||
|
"StyleCop.CSharp.NamingRules", |
||||
|
"SA1300:Element must begin with upper-case letter", |
||||
|
Justification = "Some tests must begin with lower-case letters")] |
||||
Loading…
Reference in new issue