RepeatedPrimitiveAccessor.cs 3.5 KB

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