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