GeneratedExtensionBase.cs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Text;
  5. using Google.ProtocolBuffers.Descriptors;
  6. namespace Google.ProtocolBuffers {
  7. /// <summary>
  8. /// Base type for all generated extensions.
  9. /// </summary>
  10. /// <remarks>
  11. /// The protocol compiler generates a static singleton instance of this
  12. /// class for each extension. For exmaple, imagine a .proto file with:
  13. /// <code>
  14. /// message Foo {
  15. /// extensions 1000 to max
  16. /// }
  17. ///
  18. /// extend Foo {
  19. /// optional int32 bar;
  20. /// }
  21. /// </code>
  22. /// Then MyProto.Foo.Bar has type GeneratedExtensionBase&lt;MyProto.Foo,int&gt;.
  23. /// <para />
  24. /// In general, users should ignore the details of this type, and
  25. /// simply use the static singletons as parameters to the extension accessors
  26. /// in ExtendableMessage and ExtendableBuilder.
  27. /// The interface implemented by both GeneratedException and GeneratedRepeatException,
  28. /// to make it easier to cope with repeats separately.
  29. /// </remarks>
  30. public abstract class GeneratedExtensionBase<TContainer, TExtension> {
  31. private readonly FieldDescriptor descriptor;
  32. private readonly IMessage messageDefaultInstance;
  33. protected GeneratedExtensionBase(FieldDescriptor descriptor) {
  34. if (!descriptor.IsExtension) {
  35. throw new ArgumentException("GeneratedExtension given a regular (non-extension) field.");
  36. }
  37. this.descriptor = descriptor;
  38. if (descriptor.MappedType == MappedType.Message) {
  39. PropertyInfo defaultInstanceProperty = typeof(TExtension)
  40. .GetProperty("DefaultInstance", BindingFlags.Static | BindingFlags.Public);
  41. if (defaultInstanceProperty == null) {
  42. throw new ArgumentException("No public static DefaultInstance property for type " + typeof(TExtension).Name);
  43. }
  44. messageDefaultInstance = (IMessage)defaultInstanceProperty.GetValue(null, null);
  45. }
  46. }
  47. public FieldDescriptor Descriptor {
  48. get { return descriptor; }
  49. }
  50. /// <summary>
  51. /// Returns the default message instance for extensions which are message types.
  52. /// </summary>
  53. public IMessage MessageDefaultInstance {
  54. get { return messageDefaultInstance; }
  55. }
  56. public object SingularFromReflectionType(object value) {
  57. switch (Descriptor.MappedType) {
  58. case MappedType.Message:
  59. if (value is TExtension) {
  60. return value;
  61. } else {
  62. // It seems the copy of the embedded message stored inside the
  63. // extended message is not of the exact type the user was
  64. // expecting. This can happen if a user defines a
  65. // GeneratedExtension manually and gives it a different type.
  66. // This should not happen in normal use. But, to be nice, we'll
  67. // copy the message to whatever type the caller was expecting.
  68. return MessageDefaultInstance.CreateBuilderForType()
  69. .MergeFrom((IMessage)value).Build();
  70. }
  71. case MappedType.Enum:
  72. // Just return a boxed int - that can be unboxed to the enum
  73. return ((EnumValueDescriptor) value).Number;
  74. default:
  75. return value;
  76. }
  77. }
  78. public abstract object FromReflectionType(object value);
  79. }
  80. }