DelegateWrapper.cs 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. using System;
  2. using System.Globalization;
  3. using System.Linq;
  4. using Jint.Native;
  5. using Jint.Native.Function;
  6. namespace Jint.Runtime.Interop
  7. {
  8. /// <summary>
  9. /// Represents a FunctionInstance wrapper around a CLR method. This is used by user to pass
  10. /// custom methods to the engine.
  11. /// </summary>
  12. public sealed class DelegateWrapper : FunctionInstance
  13. {
  14. private readonly Delegate _d;
  15. public DelegateWrapper(Engine engine, Delegate d) : base(engine, null, null, false)
  16. {
  17. _d = d;
  18. }
  19. public override JsValue Call(JsValue thisObject, JsValue[] jsArguments)
  20. {
  21. var parameterInfos = _d.Method.GetParameters();
  22. bool delegateContainsParamsArgument = parameterInfos.Any(p => Attribute.IsDefined(p, typeof(ParamArrayAttribute)));
  23. int delegateArgumentsCount = parameterInfos.Length;
  24. int delegateNonParamsArgumentsCount = delegateContainsParamsArgument ? delegateArgumentsCount - 1 : delegateArgumentsCount;
  25. int jsArgumentsCount = jsArguments.Length;
  26. int jsArgumentsWithoutParamsCount = Math.Min(jsArgumentsCount, delegateNonParamsArgumentsCount);
  27. var parameters = new object[delegateArgumentsCount];
  28. // convert non params parameter to expected types
  29. for (var i = 0; i < jsArgumentsWithoutParamsCount; i++)
  30. {
  31. var parameterType = parameterInfos[i].ParameterType;
  32. if (parameterType == typeof (JsValue))
  33. {
  34. parameters[i] = jsArguments[i];
  35. }
  36. else
  37. {
  38. parameters[i] = Engine.ClrTypeConverter.Convert(
  39. jsArguments[i].ToObject(),
  40. parameterType,
  41. CultureInfo.InvariantCulture);
  42. }
  43. }
  44. // assign null to parameters not provided
  45. for (var i = jsArgumentsWithoutParamsCount; i < delegateNonParamsArgumentsCount; i++)
  46. {
  47. if (parameterInfos[i].ParameterType.IsValueType)
  48. {
  49. parameters[i] = Activator.CreateInstance(parameterInfos[i].ParameterType);
  50. }
  51. else
  52. {
  53. parameters[i] = null;
  54. }
  55. }
  56. // assign params to array and converts each objet to expected type
  57. if(delegateContainsParamsArgument)
  58. {
  59. int paramsArgumentIndex = delegateArgumentsCount - 1;
  60. int paramsCount = Math.Max(0, jsArgumentsCount - delegateNonParamsArgumentsCount);
  61. object[] paramsParameter = new object[paramsCount];
  62. var paramsParameterType = parameterInfos[paramsArgumentIndex].ParameterType.GetElementType();
  63. for (var i = paramsArgumentIndex; i < jsArgumentsCount; i++)
  64. {
  65. var paramsIndex = i - paramsArgumentIndex;
  66. if (paramsParameterType == typeof(JsValue))
  67. {
  68. paramsParameter[paramsIndex] = jsArguments[i];
  69. }
  70. else
  71. {
  72. paramsParameter[paramsIndex] = Engine.ClrTypeConverter.Convert(
  73. jsArguments[i].ToObject(),
  74. paramsParameterType,
  75. CultureInfo.InvariantCulture);
  76. }
  77. }
  78. parameters[paramsArgumentIndex] = paramsParameter;
  79. }
  80. return JsValue.FromObject(Engine, _d.DynamicInvoke(parameters));
  81. }
  82. }
  83. }