GeneratedExtensionBase.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Collections;
  36. using System.Collections.Generic;
  37. using System.Reflection;
  38. using Google.ProtocolBuffers.Descriptors;
  39. namespace Google.ProtocolBuffers
  40. {
  41. /// <summary>
  42. /// Base type for all generated extensions.
  43. /// </summary>
  44. /// <remarks>
  45. /// The protocol compiler generates a static singleton instance of this
  46. /// class for each extension. For exmaple, imagine a .proto file with:
  47. /// <code>
  48. /// message Foo {
  49. /// extensions 1000 to max
  50. /// }
  51. ///
  52. /// extend Foo {
  53. /// optional int32 bar;
  54. /// }
  55. /// </code>
  56. /// Then MyProto.Foo.Bar has type GeneratedExtensionBase&lt;MyProto.Foo,int&gt;.
  57. /// <para />
  58. /// In general, users should ignore the details of this type, and
  59. /// simply use the static singletons as parameters to the extension accessors
  60. /// in ExtendableMessage and ExtendableBuilder.
  61. /// The interface implemented by both GeneratedException and GeneratedRepeatException,
  62. /// to make it easier to cope with repeats separately.
  63. /// </remarks>
  64. public abstract class GeneratedExtensionBase<TExtension>
  65. {
  66. private readonly FieldDescriptor descriptor;
  67. private readonly IMessageLite messageDefaultInstance;
  68. protected GeneratedExtensionBase(FieldDescriptor descriptor, Type singularExtensionType)
  69. {
  70. if (!descriptor.IsExtension)
  71. {
  72. throw new ArgumentException("GeneratedExtension given a regular (non-extension) field.");
  73. }
  74. this.descriptor = descriptor;
  75. if (descriptor.MappedType == MappedType.Message)
  76. {
  77. PropertyInfo defaultInstanceProperty = singularExtensionType
  78. .GetProperty("DefaultInstance", BindingFlags.Static | BindingFlags.Public);
  79. if (defaultInstanceProperty == null)
  80. {
  81. throw new ArgumentException("No public static DefaultInstance property for type " +
  82. typeof(TExtension).Name);
  83. }
  84. messageDefaultInstance = (IMessageLite) defaultInstanceProperty.GetValue(null, null);
  85. }
  86. }
  87. public FieldDescriptor Descriptor
  88. {
  89. get { return descriptor; }
  90. }
  91. public int Number
  92. {
  93. get { return Descriptor.FieldNumber; }
  94. }
  95. /// <summary>
  96. /// Returns the default message instance for extensions which are message types.
  97. /// </summary>
  98. public IMessageLite MessageDefaultInstance
  99. {
  100. get { return messageDefaultInstance; }
  101. }
  102. public object SingularFromReflectionType(object value)
  103. {
  104. switch (Descriptor.MappedType)
  105. {
  106. case MappedType.Message:
  107. if (value is TExtension)
  108. {
  109. return value;
  110. }
  111. else
  112. {
  113. // It seems the copy of the embedded message stored inside the
  114. // extended message is not of the exact type the user was
  115. // expecting. This can happen if a user defines a
  116. // GeneratedExtension manually and gives it a different type.
  117. // This should not happen in normal use. But, to be nice, we'll
  118. // copy the message to whatever type the caller was expecting.
  119. return MessageDefaultInstance.WeakCreateBuilderForType()
  120. .WeakMergeFrom((IMessageLite) value).WeakBuild();
  121. }
  122. case MappedType.Enum:
  123. // Just return a boxed int - that can be unboxed to the enum
  124. EnumValueDescriptor enumValue = (EnumValueDescriptor) value;
  125. return enumValue.Number;
  126. default:
  127. return value;
  128. }
  129. }
  130. /// <summary>
  131. /// Converts from the type used by the native accessors to the type
  132. /// used by reflection accessors. For example, the reflection accessors
  133. /// for enums use EnumValueDescriptors but the native accessors use
  134. /// the generated enum type.
  135. /// </summary>
  136. public object ToReflectionType(object value)
  137. {
  138. if (descriptor.IsRepeated)
  139. {
  140. if (descriptor.MappedType == MappedType.Enum)
  141. {
  142. // Must convert the whole list.
  143. IList<object> result = new List<object>();
  144. foreach (object element in (IEnumerable) value)
  145. {
  146. result.Add(SingularToReflectionType(element));
  147. }
  148. return result;
  149. }
  150. else
  151. {
  152. return value;
  153. }
  154. }
  155. else
  156. {
  157. return SingularToReflectionType(value);
  158. }
  159. }
  160. /// <summary>
  161. /// Like ToReflectionType(object) but for a single element.
  162. /// </summary>
  163. internal Object SingularToReflectionType(object value)
  164. {
  165. return descriptor.MappedType == MappedType.Enum
  166. ? descriptor.EnumType.FindValueByNumber((int) value)
  167. : value;
  168. }
  169. public abstract object FromReflectionType(object value);
  170. }
  171. }