DefaultTypeConverter.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System;
  2. using System.Collections.ObjectModel;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using Jint.Native;
  6. namespace Jint.Runtime.Interop
  7. {
  8. public class DefaultTypeConverter : ITypeConverter
  9. {
  10. private readonly Engine _engine;
  11. public DefaultTypeConverter(Engine engine)
  12. {
  13. _engine = engine;
  14. }
  15. public object Convert(object value, Type type, IFormatProvider formatProvider)
  16. {
  17. // don't try to convert if value is derived from type
  18. if (type.IsInstanceOfType(value))
  19. {
  20. return value;
  21. }
  22. if (type.IsEnum)
  23. {
  24. var integer = System.Convert.ChangeType(value, typeof (int), formatProvider);
  25. if (integer == null)
  26. {
  27. throw new ArgumentOutOfRangeException();
  28. }
  29. return Enum.ToObject(type, integer);
  30. }
  31. var valueType = value.GetType();
  32. // is the javascript value an ICallable instance ?
  33. if (valueType == typeof (Func<JsValue, JsValue[], JsValue>))
  34. {
  35. var function = (Func<JsValue, JsValue[], JsValue>) value;
  36. if (type.IsGenericType)
  37. {
  38. var genericType = type.GetGenericTypeDefinition();
  39. // create the requested Delegate
  40. if (genericType.Name.StartsWith("Action"))
  41. {
  42. var genericArguments = type.GetGenericArguments();
  43. var @params = new ParameterExpression[genericArguments.Count()];
  44. for (var i = 0; i < @params.Count(); i++)
  45. {
  46. @params[i] = Expression.Parameter(genericArguments[i], genericArguments[i].Name + i);
  47. }
  48. var @vars = Expression.NewArrayInit(typeof(JsValue), @params.Select(p => Expression.Call(null, typeof(JsValue).GetMethod("FromObject"), Expression.Constant(_engine, typeof(Engine)), p)));
  49. var callExpresion = Expression.Block(Expression.Call(
  50. Expression.Call(Expression.Constant(function.Target),
  51. function.Method,
  52. Expression.Constant(JsValue.Undefined, typeof(JsValue)),
  53. @vars),
  54. typeof(JsValue).GetMethod("ToObject")), Expression.Empty());
  55. return Expression.Lambda(callExpresion, new ReadOnlyCollection<ParameterExpression>(@params));
  56. }
  57. else if (genericType.Name.StartsWith("Func"))
  58. {
  59. var genericArguments = type.GetGenericArguments();
  60. var returnType = genericArguments.Last();
  61. var @params = new ParameterExpression[genericArguments.Count() - 1];
  62. for (var i = 0; i < @params.Count(); i++)
  63. {
  64. @params[i] = Expression.Parameter(genericArguments[i], genericArguments[i].Name + i);
  65. }
  66. var @vars = Expression.NewArrayInit(typeof(JsValue), @params.Select(p => Expression.Call(null, typeof(JsValue).GetMethod("FromObject"), Expression.Constant(_engine, typeof(Engine)), p)));
  67. var callExpresion = Expression.Convert(
  68. Expression.Call(
  69. Expression.Call(Expression.Constant(function.Target),
  70. function.Method,
  71. Expression.Constant(JsValue.Undefined, typeof(JsValue)),
  72. @vars),
  73. typeof(JsValue).GetMethod("ToObject")),
  74. returnType);
  75. return Expression.Lambda(callExpresion, new ReadOnlyCollection<ParameterExpression>(@params));
  76. }
  77. }
  78. else
  79. {
  80. if (type == typeof (Action))
  81. {
  82. return (Action)(() => function(JsValue.Undefined, new JsValue[0]));
  83. }
  84. }
  85. }
  86. return System.Convert.ChangeType(value, type, formatProvider);
  87. }
  88. }
  89. }