GeneratedExtensionBase.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Reflection;
  20. using Google.ProtocolBuffers.Descriptors;
  21. namespace Google.ProtocolBuffers {
  22. /// <summary>
  23. /// Base type for all generated extensions.
  24. /// </summary>
  25. /// <remarks>
  26. /// The protocol compiler generates a static singleton instance of this
  27. /// class for each extension. For exmaple, imagine a .proto file with:
  28. /// <code>
  29. /// message Foo {
  30. /// extensions 1000 to max
  31. /// }
  32. ///
  33. /// extend Foo {
  34. /// optional int32 bar;
  35. /// }
  36. /// </code>
  37. /// Then MyProto.Foo.Bar has type GeneratedExtensionBase&lt;MyProto.Foo,int&gt;.
  38. /// <para />
  39. /// In general, users should ignore the details of this type, and
  40. /// simply use the static singletons as parameters to the extension accessors
  41. /// in ExtendableMessage and ExtendableBuilder.
  42. /// The interface implemented by both GeneratedException and GeneratedRepeatException,
  43. /// to make it easier to cope with repeats separately.
  44. /// </remarks>
  45. public abstract class GeneratedExtensionBase<TExtension> {
  46. private readonly FieldDescriptor descriptor;
  47. private readonly IMessage messageDefaultInstance;
  48. protected GeneratedExtensionBase(FieldDescriptor descriptor, Type singularExtensionType) {
  49. if (!descriptor.IsExtension) {
  50. throw new ArgumentException("GeneratedExtension given a regular (non-extension) field.");
  51. }
  52. this.descriptor = descriptor;
  53. if (descriptor.MappedType == MappedType.Message) {
  54. PropertyInfo defaultInstanceProperty = singularExtensionType
  55. .GetProperty("DefaultInstance", BindingFlags.Static | BindingFlags.Public);
  56. if (defaultInstanceProperty == null) {
  57. throw new ArgumentException("No public static DefaultInstance property for type " + typeof(TExtension).Name);
  58. }
  59. messageDefaultInstance = (IMessage)defaultInstanceProperty.GetValue(null, null);
  60. }
  61. }
  62. public FieldDescriptor Descriptor {
  63. get { return descriptor; }
  64. }
  65. /// <summary>
  66. /// Returns the default message instance for extensions which are message types.
  67. /// </summary>
  68. public IMessage MessageDefaultInstance {
  69. get { return messageDefaultInstance; }
  70. }
  71. public object SingularFromReflectionType(object value) {
  72. switch (Descriptor.MappedType) {
  73. case MappedType.Message:
  74. if (value is TExtension) {
  75. return value;
  76. } else {
  77. // It seems the copy of the embedded message stored inside the
  78. // extended message is not of the exact type the user was
  79. // expecting. This can happen if a user defines a
  80. // GeneratedExtension manually and gives it a different type.
  81. // This should not happen in normal use. But, to be nice, we'll
  82. // copy the message to whatever type the caller was expecting.
  83. return MessageDefaultInstance.WeakCreateBuilderForType()
  84. .WeakMergeFrom((IMessage)value).WeakBuild();
  85. }
  86. case MappedType.Enum:
  87. // Just return a boxed int - that can be unboxed to the enum
  88. EnumValueDescriptor enumValue = (EnumValueDescriptor) value;
  89. return enumValue.Number;
  90. default:
  91. return value;
  92. }
  93. }
  94. /// <summary>
  95. /// Converts from the type used by the native accessors to the type
  96. /// used by reflection accessors. For example, the reflection accessors
  97. /// for enums use EnumValueDescriptors but the native accessors use
  98. /// the generated enum type.
  99. /// </summary>
  100. public object ToReflectionType(object value) {
  101. if (descriptor.IsRepeated) {
  102. if (descriptor.MappedType == MappedType.Enum) {
  103. // Must convert the whole list.
  104. IList<object> result = new List<object>();
  105. foreach (object element in (IEnumerable) value) {
  106. result.Add(SingularToReflectionType(element));
  107. }
  108. return result;
  109. } else {
  110. return value;
  111. }
  112. } else {
  113. return SingularToReflectionType(value);
  114. }
  115. }
  116. /// <summary>
  117. /// Like ToReflectionType(object) but for a single element.
  118. /// </summary>
  119. internal Object SingularToReflectionType(object value) {
  120. return descriptor.MappedType == MappedType.Enum
  121. ? descriptor.EnumType.FindValueByNumber((int) value)
  122. : value;
  123. }
  124. public abstract object FromReflectionType(object value);
  125. }
  126. }