• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc.  All rights reserved.
4 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using System;
11 using System.Reflection;
12 using Google.Protobuf.Compatibility;
13 
14 namespace Google.Protobuf.Reflection
15 {
16     /// <summary>
17     /// Reflection access for a oneof, allowing clear and "get case" actions.
18     /// </summary>
19     public sealed class OneofAccessor
20     {
21         private readonly Func<IMessage, int> caseDelegate;
22         private readonly Action<IMessage> clearDelegate;
23 
OneofAccessor(OneofDescriptor descriptor, Func<IMessage, int> caseDelegate, Action<IMessage> clearDelegate)24         private OneofAccessor(OneofDescriptor descriptor, Func<IMessage, int> caseDelegate, Action<IMessage> clearDelegate)
25         {
26             Descriptor = descriptor;
27             this.caseDelegate = caseDelegate;
28             this.clearDelegate = clearDelegate;
29         }
30 
ForRegularOneof( OneofDescriptor descriptor, PropertyInfo caseProperty, MethodInfo clearMethod)31         internal static OneofAccessor ForRegularOneof(
32             OneofDescriptor descriptor,
33             PropertyInfo caseProperty,
34             MethodInfo clearMethod) =>
35             new OneofAccessor(
36                 descriptor,
37                 ReflectionUtil.CreateFuncIMessageInt32(caseProperty.GetGetMethod()),
38                 ReflectionUtil.CreateActionIMessage(clearMethod));
39 
ForSyntheticOneof(OneofDescriptor descriptor)40         internal static OneofAccessor ForSyntheticOneof(OneofDescriptor descriptor)
41         {
42             // Note: descriptor.Fields will be null when this method is called, because we haven't
43             // cross-linked yet. But by the time the delegates are called by user code, all will be
44             // well. (That's why we capture the descriptor itself rather than a field.)
45             return new OneofAccessor(descriptor,
46                 message => descriptor.Fields[0].Accessor.HasValue(message) ? descriptor.Fields[0].FieldNumber : 0,
47                 message => descriptor.Fields[0].Accessor.Clear(message));
48         }
49 
50         /// <summary>
51         /// Gets the descriptor for this oneof.
52         /// </summary>
53         /// <value>
54         /// The descriptor of the oneof.
55         /// </value>
56         public OneofDescriptor Descriptor { get; }
57 
58         /// <summary>
59         /// Clears the oneof in the specified message.
60         /// </summary>
61         public void Clear(IMessage message) => clearDelegate(message);
62 
63         /// <summary>
64         /// Indicates which field in the oneof is set for specified message
65         /// </summary>
GetCaseFieldDescriptor(IMessage message)66         public FieldDescriptor GetCaseFieldDescriptor(IMessage message)
67         {
68             int fieldNumber = caseDelegate(message);
69             return fieldNumber > 0
70                 ? Descriptor.ContainingType.FindFieldByNumber(fieldNumber)
71                 : null;
72         }
73     }
74 }
75