MethodAccessorPlugin.cs 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Avalonia.Data;
  5. using System.Reflection;
  6. using System.Linq;
  7. namespace Avalonia.Data.Core.Plugins
  8. {
  9. class MethodAccessorPlugin : IPropertyAccessorPlugin
  10. {
  11. public bool Match(object obj, string methodName)
  12. => obj.GetType().GetRuntimeMethods().Any(x => x.Name == methodName);
  13. public IPropertyAccessor Start(WeakReference reference, string methodName)
  14. {
  15. Contract.Requires<ArgumentNullException>(reference != null);
  16. Contract.Requires<ArgumentNullException>(methodName != null);
  17. var instance = reference.Target;
  18. var method = instance.GetType().GetRuntimeMethods().FirstOrDefault(x => x.Name == methodName);
  19. if (method != null)
  20. {
  21. if (method.GetParameters().Length + (method.ReturnType == typeof(void) ? 0 : 1) > 8)
  22. {
  23. var exception = new ArgumentException("Cannot create a binding accessor for a method with more than 8 parameters or more than 7 parameters if it has a non-void return type.", nameof(method));
  24. return new PropertyError(new BindingNotification(exception, BindingErrorType.Error));
  25. }
  26. return new Accessor(reference, method);
  27. }
  28. else
  29. {
  30. var message = $"Could not find CLR method '{methodName}' on '{instance}'";
  31. var exception = new MissingMemberException(message);
  32. return new PropertyError(new BindingNotification(exception, BindingErrorType.Error));
  33. }
  34. }
  35. private class Accessor : PropertyAccessorBase
  36. {
  37. public Accessor(WeakReference reference, MethodInfo method)
  38. {
  39. Contract.Requires<ArgumentNullException>(reference != null);
  40. Contract.Requires<ArgumentNullException>(method != null);
  41. var paramTypes = method.GetParameters().Select(param => param.ParameterType).ToArray();
  42. var returnType = method.ReturnType;
  43. if (returnType == typeof(void))
  44. {
  45. if (paramTypes.Length == 0)
  46. {
  47. PropertyType = typeof(Action);
  48. }
  49. else
  50. {
  51. PropertyType = Type.GetType($"System.Action`{paramTypes.Length}").MakeGenericType(paramTypes);
  52. }
  53. }
  54. else
  55. {
  56. var genericTypeParameters = paramTypes.Concat(new[] { returnType }).ToArray();
  57. PropertyType = Type.GetType($"System.Func`{genericTypeParameters.Length}").MakeGenericType(genericTypeParameters);
  58. }
  59. Value = method.IsStatic ? method.CreateDelegate(PropertyType) : method.CreateDelegate(PropertyType, reference.Target);
  60. }
  61. public override Type PropertyType { get; }
  62. public override object Value { get; }
  63. public override bool SetValue(object value, BindingPriority priority) => false;
  64. protected override void SubscribeCore()
  65. {
  66. try
  67. {
  68. PublishValue(Value);
  69. }
  70. catch { }
  71. }
  72. protected override void UnsubscribeCore()
  73. {
  74. }
  75. }
  76. }
  77. }