RepeatedPrimitiveAccessor.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using System;
  2. using System.Collections;
  3. using System.Reflection;
  4. using Google.ProtocolBuffers.Descriptors;
  5. namespace Google.ProtocolBuffers.FieldAccess {
  6. /// <summary>
  7. /// Accesor for a repeated field of type int, ByteString etc.
  8. /// </summary>
  9. internal class RepeatedPrimitiveAccessor : IFieldAccessor {
  10. private readonly PropertyInfo messageProperty;
  11. private readonly PropertyInfo builderProperty;
  12. private readonly PropertyInfo hasProperty;
  13. private readonly PropertyInfo countProperty;
  14. private readonly MethodInfo clearMethod;
  15. private readonly MethodInfo addMethod;
  16. private readonly MethodInfo getElementMethod;
  17. private readonly MethodInfo setElementMethod;
  18. /// <summary>
  19. /// The CLR type of the field (int, the enum type, ByteString, the message etc).
  20. /// This is taken from the return type of the method used to retrieve a single
  21. /// value.
  22. /// </summary>
  23. protected Type ClrType {
  24. get { return getElementMethod.ReturnType; }
  25. }
  26. internal RepeatedPrimitiveAccessor(string name, Type messageType, Type builderType) {
  27. messageProperty = messageType.GetProperty(name + "List");
  28. builderProperty = builderType.GetProperty(name + "List");
  29. hasProperty = messageType.GetProperty("Has" + name);
  30. countProperty = messageType.GetProperty(name + "Count");
  31. clearMethod = builderType.GetMethod("Clear" + name);
  32. addMethod = builderType.GetMethod("Add" + name);
  33. getElementMethod = messageType.GetMethod("Get" + name, new Type[] { typeof(int) });
  34. setElementMethod = builderType.GetMethod("Set" + name, new Type[] { typeof(int) });
  35. if (messageProperty == null
  36. || builderProperty == null
  37. || hasProperty == null
  38. || countProperty == null
  39. || clearMethod == null
  40. || addMethod == null
  41. || getElementMethod == null
  42. || setElementMethod == null) {
  43. throw new ArgumentException("Not all required properties/methods available");
  44. }
  45. }
  46. public bool Has(IMessage message) {
  47. throw new InvalidOperationException();
  48. }
  49. public virtual IBuilder CreateBuilder() {
  50. throw new InvalidOperationException();
  51. }
  52. public virtual object GetValue(IMessage message) {
  53. return messageProperty.GetValue(message, null);
  54. }
  55. public void SetValue(IBuilder builder, object value) {
  56. // Add all the elements individually. This serves two purposes:
  57. // 1) Verifies that each element has the correct type.
  58. // 2) Insures that the caller cannot modify the list later on and
  59. // have the modifications be reflected in the message.
  60. Clear(builder);
  61. foreach (object element in (IEnumerable) value) {
  62. AddRepeated(builder, element);
  63. }
  64. }
  65. public void Clear(IBuilder builder) {
  66. clearMethod.Invoke(builder, null);
  67. }
  68. public int GetRepeatedCount(IMessage message) {
  69. return (int) countProperty.GetValue(null, null);
  70. }
  71. public virtual object GetRepeatedValue(IMessage message, int index) {
  72. return getElementMethod.Invoke(message, new object[] {index } );
  73. }
  74. public virtual void SetRepeated(IBuilder builder, int index, object value) {
  75. setElementMethod.Invoke(builder, new object[] {index, value} );
  76. }
  77. public virtual void AddRepeated(IBuilder builder, object value) {
  78. addMethod.Invoke(builder, new object[] { value });
  79. }
  80. /// <summary>
  81. /// The builder class's accessor already builds a read-only wrapper for
  82. /// us, which is exactly what we want.
  83. /// </summary>
  84. public object GetRepeatedWrapper(IBuilder builder) {
  85. return builderProperty.GetValue(builder, null);
  86. }
  87. }
  88. }