ProtoMemberAttribute.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using System;
  2. using System.Reflection;
  3. namespace ProtoBuf
  4. {
  5. /// <summary>
  6. /// Declares a member to be used in protocol-buffer serialization, using
  7. /// the given Tag. A DataFormat may be used to optimise the serialization
  8. /// format (for instance, using zigzag encoding for negative numbers, or
  9. /// fixed-length encoding for large values.
  10. /// </summary>
  11. [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
  12. AllowMultiple = false, Inherited = true)]
  13. public class ProtoMemberAttribute : Attribute
  14. , IComparable
  15. , IComparable<ProtoMemberAttribute>
  16. {
  17. /// <summary>
  18. /// Compare with another ProtoMemberAttribute for sorting purposes
  19. /// </summary>
  20. public int CompareTo(object other) => CompareTo(other as ProtoMemberAttribute);
  21. /// <summary>
  22. /// Compare with another ProtoMemberAttribute for sorting purposes
  23. /// </summary>
  24. public int CompareTo(ProtoMemberAttribute other)
  25. {
  26. if (other == null) return -1;
  27. if ((object)this == (object)other) return 0;
  28. int result = this.tag.CompareTo(other.tag);
  29. if (result == 0) result = string.CompareOrdinal(this.name, other.name);
  30. return result;
  31. }
  32. /// <summary>
  33. /// Creates a new ProtoMemberAttribute instance.
  34. /// </summary>
  35. /// <param name="tag">Specifies the unique tag used to identify this member within the type.</param>
  36. public ProtoMemberAttribute(int tag) : this(tag, false)
  37. { }
  38. internal ProtoMemberAttribute(int tag, bool forced)
  39. {
  40. if (tag <= 0 && !forced) throw new ArgumentOutOfRangeException(nameof(tag));
  41. this.tag = tag;
  42. }
  43. #if !NO_RUNTIME
  44. internal MemberInfo Member, BackingMember;
  45. internal bool TagIsPinned;
  46. #endif
  47. /// <summary>
  48. /// Gets or sets the original name defined in the .proto; not used
  49. /// during serialization.
  50. /// </summary>
  51. public string Name { get { return name; } set { name = value; } }
  52. private string name;
  53. /// <summary>
  54. /// Gets or sets the data-format to be used when encoding this value.
  55. /// </summary>
  56. public DataFormat DataFormat { get { return dataFormat; } set { dataFormat = value; } }
  57. private DataFormat dataFormat;
  58. /// <summary>
  59. /// Gets the unique tag used to identify this member within the type.
  60. /// </summary>
  61. public int Tag { get { return tag; } }
  62. private int tag;
  63. internal void Rebase(int tag) { this.tag = tag; }
  64. /// <summary>
  65. /// Gets or sets a value indicating whether this member is mandatory.
  66. /// </summary>
  67. public bool IsRequired
  68. {
  69. get { return (options & MemberSerializationOptions.Required) == MemberSerializationOptions.Required; }
  70. set
  71. {
  72. if (value) options |= MemberSerializationOptions.Required;
  73. else options &= ~MemberSerializationOptions.Required;
  74. }
  75. }
  76. /// <summary>
  77. /// Gets a value indicating whether this member is packed.
  78. /// This option only applies to list/array data of primitive types (int, double, etc).
  79. /// </summary>
  80. public bool IsPacked
  81. {
  82. get { return (options & MemberSerializationOptions.Packed) == MemberSerializationOptions.Packed; }
  83. set
  84. {
  85. if (value) options |= MemberSerializationOptions.Packed;
  86. else options &= ~MemberSerializationOptions.Packed;
  87. }
  88. }
  89. /// <summary>
  90. /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
  91. /// This option only applies to list/array data.
  92. /// </summary>
  93. public bool OverwriteList
  94. {
  95. get { return (options & MemberSerializationOptions.OverwriteList) == MemberSerializationOptions.OverwriteList; }
  96. set
  97. {
  98. if (value) options |= MemberSerializationOptions.OverwriteList;
  99. else options &= ~MemberSerializationOptions.OverwriteList;
  100. }
  101. }
  102. /// <summary>
  103. /// Enables full object-tracking/full-graph support.
  104. /// </summary>
  105. public bool AsReference
  106. {
  107. get { return (options & MemberSerializationOptions.AsReference) == MemberSerializationOptions.AsReference; }
  108. set
  109. {
  110. if (value) options |= MemberSerializationOptions.AsReference;
  111. else options &= ~MemberSerializationOptions.AsReference;
  112. options |= MemberSerializationOptions.AsReferenceHasValue;
  113. }
  114. }
  115. internal bool AsReferenceHasValue
  116. {
  117. get { return (options & MemberSerializationOptions.AsReferenceHasValue) == MemberSerializationOptions.AsReferenceHasValue; }
  118. set
  119. {
  120. if (value) options |= MemberSerializationOptions.AsReferenceHasValue;
  121. else options &= ~MemberSerializationOptions.AsReferenceHasValue;
  122. }
  123. }
  124. /// <summary>
  125. /// Embeds the type information into the stream, allowing usage with types not known in advance.
  126. /// </summary>
  127. public bool DynamicType
  128. {
  129. get { return (options & MemberSerializationOptions.DynamicType) == MemberSerializationOptions.DynamicType; }
  130. set
  131. {
  132. if (value) options |= MemberSerializationOptions.DynamicType;
  133. else options &= ~MemberSerializationOptions.DynamicType;
  134. }
  135. }
  136. /// <summary>
  137. /// Gets or sets a value indicating whether this member is packed (lists/arrays).
  138. /// </summary>
  139. public MemberSerializationOptions Options { get { return options; } set { options = value; } }
  140. private MemberSerializationOptions options;
  141. }
  142. /// <summary>
  143. /// Additional (optional) settings that control serialization of members
  144. /// </summary>
  145. [Flags]
  146. public enum MemberSerializationOptions
  147. {
  148. /// <summary>
  149. /// Default; no additional options
  150. /// </summary>
  151. None = 0,
  152. /// <summary>
  153. /// Indicates that repeated elements should use packed (length-prefixed) encoding
  154. /// </summary>
  155. Packed = 1,
  156. /// <summary>
  157. /// Indicates that the given item is required
  158. /// </summary>
  159. Required = 2,
  160. /// <summary>
  161. /// Enables full object-tracking/full-graph support
  162. /// </summary>
  163. AsReference = 4,
  164. /// <summary>
  165. /// Embeds the type information into the stream, allowing usage with types not known in advance
  166. /// </summary>
  167. DynamicType = 8,
  168. /// <summary>
  169. /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
  170. /// This option only applies to list/array data.
  171. /// </summary>
  172. OverwriteList = 16,
  173. /// <summary>
  174. /// Determines whether the types AsReferenceDefault value is used, or whether this member's AsReference should be used
  175. /// </summary>
  176. AsReferenceHasValue = 32
  177. }
  178. /// <summary>
  179. /// Declares a member to be used in protocol-buffer serialization, using
  180. /// the given Tag and MemberName. This allows ProtoMemberAttribute usage
  181. /// even for partial classes where the individual members are not
  182. /// under direct control.
  183. /// A DataFormat may be used to optimise the serialization
  184. /// format (for instance, using zigzag encoding for negative numbers, or
  185. /// fixed-length encoding for large values.
  186. /// </summary>
  187. [AttributeUsage(AttributeTargets.Class,
  188. AllowMultiple = true, Inherited = false)]
  189. public sealed class ProtoPartialMemberAttribute : ProtoMemberAttribute
  190. {
  191. /// <summary>
  192. /// Creates a new ProtoMemberAttribute instance.
  193. /// </summary>
  194. /// <param name="tag">Specifies the unique tag used to identify this member within the type.</param>
  195. /// <param name="memberName">Specifies the member to be serialized.</param>
  196. public ProtoPartialMemberAttribute(int tag, string memberName)
  197. : base(tag)
  198. {
  199. #if !NO_RUNTIME
  200. if (string.IsNullOrEmpty(memberName)) throw new ArgumentNullException(nameof(memberName));
  201. #endif
  202. this.MemberName = memberName;
  203. }
  204. /// <summary>
  205. /// The name of the member to be serialized.
  206. /// </summary>
  207. public string MemberName { get; private set; }
  208. }
  209. }