ArrayBehavior.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace ClaySharp.Behaviors {
  6. public class ArrayBehavior : ClayBehavior {
  7. readonly List<object> _data = new List<object>();
  8. public override object GetIndex(Func<object> proceed, object self, IEnumerable<object> keys) {
  9. return IfSingleInteger(keys, key => _data[key], proceed);
  10. }
  11. public override object SetIndex(Func<object> proceed, object self, IEnumerable<object> keys, object value) {
  12. return IfSingleInteger(keys, key => _data[key] = value, proceed);
  13. }
  14. public override object GetMember(Func<object> proceed, object self, string name) {
  15. switch (name) {
  16. case "Length":
  17. case "Count":
  18. return _data.Count;
  19. case "GetEnumerator":
  20. return new Clay(new InterfaceProxyBehavior(), new EnumeratorBehavior(_data.GetEnumerator()));
  21. }
  22. return proceed();
  23. }
  24. public override object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
  25. switch (name) {
  26. case "AddRange":
  27. _data.AddRange(((IEnumerable)args.Single()).OfType<object>());
  28. return self;
  29. case "Add":
  30. _data.AddRange(args);
  31. return self;
  32. case "Insert":
  33. return IfInitialInteger(args, (index, arr) => { _data.InsertRange(index, arr); return self; }, proceed);
  34. case "RemoveAt":
  35. return IfSingleInteger(args, index => { _data.RemoveAt(index); return self; }, proceed);
  36. case "Contains":
  37. return IfSingleArgument(args, arg => _data.Contains(arg), proceed);
  38. case "IndexOf":
  39. return IfSingleArgument(args, arg => _data.IndexOf(arg), proceed);
  40. case "Remove":
  41. return IfSingleArgument(args, arg => _data.Remove(arg), proceed);
  42. case "CopyTo":
  43. return IfArguments<object[], int>(args, (array, arrayIndex) => {
  44. _data.CopyTo(array, arrayIndex);
  45. return self;
  46. }, proceed);
  47. }
  48. if (!args.Any()) {
  49. return GetMember(proceed, self, name);
  50. }
  51. return proceed();
  52. }
  53. private static object IfArguments<T1, T2>(IEnumerable<object> args, Func<T1, T2, object> func, Func<object> proceed) {
  54. if (args.Count() != 2)
  55. return proceed();
  56. return func((T1)args.First(), (T2)args.Last());
  57. }
  58. private static object IfSingleArgument(IEnumerable<object> args, Func<object, object> func, Func<object> proceed) {
  59. return args.Count() == 1 ? func(args.Single()) : proceed();
  60. }
  61. private static object IfSingleInteger(IEnumerable<object> args, Func<int, object> func, Func<object> proceed) {
  62. if (args.Count() != 1)
  63. return proceed();
  64. return IfInitialInteger(args, (index, ignored) => func(index), proceed);
  65. }
  66. private static object IfInitialInteger(IEnumerable<object> args, Func<int, IEnumerable<object>, object> func, Func<object> proceed) {
  67. if (!args.Any())
  68. return proceed();
  69. var key = args.First();
  70. if (key.GetType() != typeof(int))
  71. return proceed();
  72. return func((int)key, args.Skip(1));
  73. }
  74. // small, dynamic wrapper around underlying IEnumerator. use of
  75. // dlr and dynamic proxy enables this enumerator to be used in places
  76. // where the array is being cast into a strong collection interface
  77. class EnumeratorBehavior : ClayBehavior {
  78. private readonly IEnumerator _enumerator;
  79. public EnumeratorBehavior(IEnumerator enumerator) {
  80. _enumerator = enumerator;
  81. }
  82. public override object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
  83. switch (name) {
  84. case "MoveNext":
  85. return _enumerator.MoveNext();
  86. case "Reset":
  87. _enumerator.Reset();
  88. return null;
  89. case "Dispose":
  90. if (_enumerator is IDisposable)
  91. ((IDisposable)_enumerator).Dispose();
  92. return null;
  93. }
  94. return proceed();
  95. }
  96. public override object GetMember(Func<object> proceed, object self, string name) {
  97. switch (name) {
  98. case "Current":
  99. return _enumerator.Current;
  100. }
  101. return proceed();
  102. }
  103. }}
  104. }