ArrayBehavior.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace Masuit.Tools.Dynamics.Behaviors;
  6. internal class ArrayBehavior : ClayBehavior
  7. {
  8. private readonly List<object> _data = new();
  9. /// <inheritdoc />
  10. public override object GetIndex(Func<object> proceed, object self, IEnumerable<string> keys)
  11. {
  12. return IfSingleInteger(keys, key => _data[key], proceed);
  13. }
  14. /// <inheritdoc />
  15. public override object SetIndex(Func<object> proceed, object self, IEnumerable<string> keys, object value)
  16. {
  17. return IfSingleInteger(keys, key => _data[key] = value, proceed);
  18. }
  19. /// <inheritdoc />
  20. public override object GetMember(Func<object> proceed, object self, string name)
  21. {
  22. switch (name)
  23. {
  24. case "Length":
  25. case "Count":
  26. return _data.Count;
  27. case "GetEnumerator":
  28. return new Clay(new InterfaceProxyBehavior(), new EnumeratorBehavior(_data.GetEnumerator()));
  29. }
  30. return proceed();
  31. }
  32. /// <inheritdoc />
  33. public override object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args)
  34. {
  35. switch (name)
  36. {
  37. case "AddRange":
  38. _data.AddRange(((IEnumerable)args.Single()).OfType<object>());
  39. return self;
  40. case "Add":
  41. _data.AddRange(args);
  42. return self;
  43. case "Insert":
  44. return IfInitialInteger(args, (index, arr) => { _data.InsertRange(index, arr); return self; }, proceed);
  45. case "RemoveAt":
  46. return IfSingleInteger(args, index => { _data.RemoveAt(index); return self; }, proceed);
  47. case "Contains":
  48. return IfSingleArgument(args, arg => _data.Contains(arg), proceed);
  49. case "IndexOf":
  50. return IfSingleArgument(args, arg => _data.IndexOf(arg), proceed);
  51. case "Remove":
  52. return IfSingleArgument(args, arg => _data.Remove(arg), proceed);
  53. case "CopyTo":
  54. return IfArguments<object[], int>(args, (array, arrayIndex) =>
  55. {
  56. _data.CopyTo(array, arrayIndex);
  57. return self;
  58. }, proceed);
  59. }
  60. if (!args.Any())
  61. {
  62. return GetMember(proceed, self, name);
  63. }
  64. return proceed();
  65. }
  66. private static object IfArguments<T1, T2>(IEnumerable<object> args, Func<T1, T2, object> func, Func<object> proceed)
  67. {
  68. var objects = args as List<object> ?? args.ToList();
  69. return objects.Count != 2 ? proceed() : func((T1)objects[0], (T2)objects.Last());
  70. }
  71. private static object IfSingleArgument(IEnumerable<object> args, Func<object, object> func, Func<object> proceed)
  72. {
  73. var objects = args as List<object> ?? args.ToList();
  74. return objects.Count == 1 ? func(objects[0]) : proceed();
  75. }
  76. private static object IfSingleInteger(IEnumerable<object> args, Func<int, object> func, Func<object> proceed)
  77. {
  78. var objects = args as List<object> ?? args.ToList();
  79. return objects.Count != 1 ? proceed() : IfInitialInteger(objects, (index, _) => func(index), proceed);
  80. }
  81. private static object IfInitialInteger(IEnumerable<object> args, Func<int, IEnumerable<object>, object> func, Func<object> proceed)
  82. {
  83. var objects = args as List<object> ?? args.ToList();
  84. if (objects.Count > 0)
  85. {
  86. var key = objects[0];
  87. return key.GetType() != typeof(int) ? proceed() : func((int)key, objects.Skip(1));
  88. }
  89. return proceed();
  90. }
  91. private class EnumeratorBehavior : ClayBehavior
  92. {
  93. private readonly IEnumerator _enumerator;
  94. public EnumeratorBehavior(IEnumerator enumerator)
  95. {
  96. _enumerator = enumerator;
  97. }
  98. public override object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args)
  99. {
  100. switch (name)
  101. {
  102. case "MoveNext":
  103. return _enumerator.MoveNext();
  104. case "Reset":
  105. _enumerator.Reset();
  106. return null;
  107. case "Dispose":
  108. if (_enumerator is IDisposable disposable)
  109. {
  110. disposable.Dispose();
  111. }
  112. return null;
  113. }
  114. return proceed();
  115. }
  116. public override object GetMember(Func<object> proceed, object self, string name)
  117. {
  118. switch (name)
  119. {
  120. case "Current":
  121. return _enumerator.Current;
  122. }
  123. return proceed();
  124. }
  125. }
  126. }