.NET Portable TypeCast  3.1.0.4
A, easy-to-use tested, generic, portable, runtime-extensible, arbitrary type converter library
ObjectExtension.cs
Go to the documentation of this file.
1 // <copyright file=mitlicense.md url=http://lsauer.mit-license.org/ >
2 // Lo Sauer, 2013-2016
3 // </copyright>
4 // <summary> A tested, generic, portable, runtime-extensible type converter library </summary
5 // <language> C# > 6.0 </language>
6 // <version> 3.1.0.2 </version>
7 // <author> Lorenz Lo Sauer; people credited in the sources </author>
8 // <project> https://github.com/lsauer/dotnet-portable-type-cast </project>
9 namespace Core.TypeCast
10 {
11  using System;
12  using System.Reflection;
13  using System.Linq;
14 
15  using System.Runtime.CompilerServices;
16  using System.Collections;
17  using System.Collections.Generic;
18 
19  using Core.TypeCast.Base;
20  using Core.Extensions;
21 
23  public static partial class ObjectExtension
24  {
25  private static Type objectType = typeof(object);
26  private static TypeInfo objectTypeInfo = typeof(object).GetTypeInfo();
27 
49  private static bool GetConverterOrDefault<TIn, TOut>(
50  TIn self,
51  out Converter converter,
52  out TOut result,
53  Type typeArgument = null,
54  Type typeTo = null,
55  Type typeBase = null,
56  bool throwException = false,
57  bool unboxObjectType = true,
58  string attributeName = null,
59  bool withContext = false)
60  {
61  ConverterCollection.AutoInitialize();
62  if(typeof(TIn) == objectType)
63  {
64  if(throwException == true && unboxObjectType == false && ConverterCollection.CurrentInstance.Settings.AllowGenericTypes == false)
65  {
66  throw new ConverterException(ConverterCause.ConverterTypeInIsExplicitObject);
67  }
68 
69  var typeFrom = unboxObjectType ? self.GetType() : objectType;
70  if(typeTo == null || typeof(TOut) != objectType)
71  {
72  typeTo = typeTo ?? typeof(TOut);
73  }
74  converter = ConverterCollection.CurrentInstance.Get(typeFrom: typeFrom.GetTypeInfo(), typeTo: typeTo?.GetTypeInfo(), typeArgument: typeArgument?.GetTypeInfo(),
75  typeBase: typeBase?.GetTypeInfo(), attributeName: attributeName, loadOnDemand: true, assignable: false, withContext: withContext);
76  // Retry by widening the search to type-inheritance
77  if(converter == null)
78  {
79  converter = ConverterCollection.CurrentInstance.Get(typeFrom: typeFrom.GetTypeInfo(), typeTo: typeTo?.GetTypeInfo(), typeArgument: typeArgument?.GetTypeInfo(),
80  typeBase: typeBase?.GetTypeInfo(), attributeName: attributeName, loadOnDemand: false, assignable: true, withContext: withContext);
81  }
82  // no specific converter found, lets find a generic fallback converter
83  if(converter == null && unboxObjectType == true && typeof(TIn) == objectType)
84  {
85  converter = ConverterCollection.CurrentInstance.Get(typeFrom: objectTypeInfo, typeTo: typeTo?.GetTypeInfo(), typeArgument: typeArgument?.GetTypeInfo(),
86  typeBase: typeBase?.GetTypeInfo(), attributeName: attributeName, loadOnDemand: false, assignable: false, withContext: withContext);
87  }
88  }
89  else
90  {
91  converter = ConverterCollection.CurrentInstance.Get<TIn, TOut>(self, typeArgument: typeArgument, loadOnDemand: true);
92  }
93 
94  if(self is TOut)
95  {
96  result = (TOut)(object)self;
97  return true;
98  }
99 
100  result = default(TOut);
101  return false;
102  }
103 
117  private static bool InvokeConvert<TIn, TOut>(TIn self, out TOut result, object defaultValue, bool throwException, Converter converter, IConvertContext contextInstance = null, [CallerMemberName] string caller = null)
118  {
119  if(defaultValue is IConvertContext)
120  {
121  contextInstance = SetContext<TIn, TOut>(defaultValue as IConvertContext, ((IConvertContext)defaultValue).Value, throwException, converter, caller);
122  }
123  else
124  {
125  contextInstance = SetContext<TIn, TOut>(contextInstance, defaultValue, throwException, converter, caller);
126  }
127 
128  if(converter != null)
129  {
130  try
131  {
132  result = (TOut)converter.Convert(self, contextInstance ?? defaultValue);
133  return IsDefaultValue<TOut>(result) == false;
134  }
135  catch(Exception exc)
136  {
137  if(exc is IException)
138  {
139  if(throwException == true)
140  {
141  throw;
142  }
143  }
144  else if(exc is System.FormatException)
145  {
146  if(throwException == true)
147  {
148  throw new ConverterException(ConverterCause.BadInputFormat, exc);
149  }
150  }
151  else if(exc is System.OverflowException || exc is System.InvalidOperationException || exc is System.ArithmeticException)
152  {
153  if(throwException == true)
154  {
155  throw new ConverterException(ConverterCause.LogicError, exc);
156  }
157  }
158  else
159  {
160  throw new ConverterException(ConverterCause.ConvertFailed, exc);
161  }
162  }
163  }
164 
165  result = default(TOut);
166 
167  if(ConverterCollection.CurrentInstance.Settings.AllowDynamicType == true)
168  {
169  // lets use the internal CLR reflection logic via `dynamic` to invoke a Type's dynamic implicit cast method if available
170  try
171  {
172  dynamic tmp = self;
173  result = (TOut)tmp;
174  return true;
175  }
176  // don't handle exceptions any further at this point
177  catch(Exception) { }
178  }
179  return false;
180  }
181 
195  private static IConvertContext SetContext<TIn, TOut>(IConvertContext contextInstance, object defaultValue, bool throwException, Converter converter, string caller)
196  {
197  if(contextInstance != null)
198  {
199  contextInstance = new ConvertContext<TIn, TOut>(defaultValue)
200  {
201  Argument = defaultValue?.GetType(),
202  Converter = contextInstance.Converter ?? converter,
203  Caller = contextInstance.Caller ?? caller,
204  ThrowExceptions = contextInstance.ThrowExceptions ?? throwException,
205  Nullable = contextInstance.Nullable ?? false
206  };
207  }
208 
209  return contextInstance;
210  }
211 
221  [MethodImpl(MethodImplOptions.AggressiveInlining)]
222  public static bool CanConvertTo<TIn, TOut>(this TIn self, TOut target = default(TOut))
223  {
224  TOut result = default(TOut);
225  Converter converter = null;
226  GetConverterOrDefault<TIn, TOut>(self, out converter, out result);
227  return converter != null;
228  }
229 
240  [MethodImpl(MethodImplOptions.AggressiveInlining)]
241  public static bool CanConvertTo<TOut, TArg>(this object self, TOut target = default(TOut), TArg model = default(TArg))
242  {
243  TOut result = default(TOut);
244  Converter converter = null;
245  GetConverterOrDefault<object, TOut>(self, out converter, out result, typeArgument: typeof(TArg), unboxObjectType: true);
246  return converter != null;
247  }
248 
259  [MethodImpl(MethodImplOptions.AggressiveInlining)]
260  public static bool CanConvertTo<TIn, TArg>(this TIn self, Type typeTo, TArg model = default(TArg))
261  {
262  object result = null;
263  Converter converter = null;
264  GetConverterOrDefault<TIn, object>(self, out converter, out result, typeTo: typeTo, typeArgument: typeof(TArg));
265  return converter != null;
266  }
267 
277  [MethodImpl(MethodImplOptions.AggressiveInlining)]
278  public static bool CanConvertTo<TIn>(this TIn self, Type typeTo, Type typeModel)
279  {
280  object result = null;
281  Converter converter = null;
282  GetConverterOrDefault<TIn, object>(self, out converter, out result, typeTo: typeTo, typeArgument: typeModel?.GetType());
283  return converter != null;
284  }
285 
294  [MethodImpl(MethodImplOptions.AggressiveInlining)]
295  public static bool CanConvertTo<TIn>(this TIn self, Type typeTo)
296  {
297  object result = null;
298  Converter converter = null;
299  GetConverterOrDefault<TIn, object>(self, out converter, out result, typeTo: typeTo, unboxObjectType: true);
300  return converter != null;
301  }
302 
310  [MethodImpl(MethodImplOptions.AggressiveInlining)]
311  public static bool CanConvertTo<TOut>(this object self)
312  {
313  TOut result = default(TOut);
314  Converter converter = null;
315  GetConverterOrDefault<object, TOut>(self, out converter, out result, unboxObjectType: true);
316  return converter != null;
317  }
318 
325  [MethodImpl(MethodImplOptions.AggressiveInlining)]
326  public static bool IsDefaultValue<TIn>(this TIn self)
327  {
328  return Object.Equals(self, default(TIn)) == true;
329  }
330 
337  [MethodImpl(MethodImplOptions.AggressiveInlining)]
338  public static bool IsDefaultValue<TIn>(this object self)
339  {
340  return Object.Equals(self, default(TIn)) == true;
341  }
342  }
343 }
ConverterCause
Contains the reasons for a ConverterException to be raised.