DelegateWrapper.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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. var parameters = new object[delegateArgumentsCount];
  26. // convert non params parameter to expected types
  27. for (var i = 0; i < delegateNonParamsArgumentsCount; i++)
  28. {
  29. var parameterType = parameterInfos[i].ParameterType;
  30. if (parameterType == typeof (JsValue))
  31. {
  32. parameters[i] = jsArguments[i];
  33. }
  34. else
  35. {
  36. parameters[i] = Engine.ClrTypeConverter.Convert(
  37. jsArguments[i].ToObject(),
  38. parameterType,
  39. CultureInfo.InvariantCulture);
  40. }
  41. }
  42. // assign null to parameters not provided
  43. for (var i = jsArguments.Length; i < delegateNonParamsArgumentsCount; i++)
  44. {
  45. if (parameterInfos[i].ParameterType.IsValueType)
  46. {
  47. parameters[i] = Activator.CreateInstance(parameterInfos[i].ParameterType);
  48. }
  49. else
  50. {
  51. parameters[i] = null;
  52. }
  53. }
  54. // assign params to array and converts each objet to expected type
  55. if(delegateContainsParamsArgument)
  56. {
  57. object[] paramsParameter = new object[jsArguments.Length - delegateNonParamsArgumentsCount];
  58. var paramsParameterType = parameterInfos[delegateArgumentsCount -1].ParameterType.GetElementType();
  59. for (var i = delegateNonParamsArgumentsCount; i < jsArguments.Length; i++)
  60. {
  61. if (paramsParameterType == typeof(JsValue))
  62. {
  63. paramsParameter[i - delegateNonParamsArgumentsCount] = jsArguments[i];
  64. }
  65. else
  66. {
  67. paramsParameter[i - delegateNonParamsArgumentsCount] = Engine.ClrTypeConverter.Convert(
  68. jsArguments[i].ToObject(),
  69. paramsParameterType,
  70. CultureInfo.InvariantCulture);
  71. }
  72. }
  73. parameters[delegateNonParamsArgumentsCount] = paramsParameter;
  74. }
  75. return JsValue.FromObject(Engine, _d.DynamicInvoke(parameters));
  76. }
  77. }
  78. }