From 7e968ac90292764368e24426d1a5e026cdbdf4d3 Mon Sep 17 00:00:00 2001 From: Jeremy Swigart Date: Wed, 10 Oct 2018 16:50:56 -0500 Subject: [PATCH 1/5] type safe c# extension identifiers - added support for type safe identifiers to be written to c# generated file so that an object can be passed in to CustomOptions.TryGet* that is safe to the type of option being passed, so mistakes like passing the wrong extension to the function will be detected at compile time - updated c# generator to write type safe extension identifiers to an extensions namespace under the package --- .../Reflection/CustomOptionsTest.cs | 116 ++++++++++-------- .../Reflection/CustomOptions.cs | 115 ++++++++++++----- .../Google.Protobuf/Reflection/Descriptor.cs | 16 +-- .../Reflection/EnumDescriptor.cs | 2 +- .../Reflection/EnumValueDescriptor.cs | 2 +- .../Reflection/FieldDescriptor.cs | 2 +- .../Reflection/FileDescriptor.cs | 2 +- .../Reflection/MessageDescriptor.cs | 2 +- .../Reflection/MethodDescriptor.cs | 2 +- .../Reflection/OneofDescriptor.cs | 2 +- .../Reflection/ServiceDescriptor.cs | 2 +- .../csharp/csharp_reflection_class.cc | 59 +++++++++ 12 files changed, 220 insertions(+), 102 deletions(-) diff --git a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs index 68b4d6af7cf8b..fca54e63dc27b 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs @@ -33,6 +33,7 @@ using Google.Protobuf.Reflection; using Google.Protobuf.WellKnownTypes; using NUnit.Framework; +using System; using System.IO; using System.Linq; using UnitTest.Issues.TestProtos; @@ -97,7 +98,7 @@ internal enum CustomOptionNumber /// public class CustomOptionsTest { - delegate bool OptionFetcher(int field, out T value); + delegate bool OptionFetcher(FieldId field, out T value); [Test] public void EmptyOptionsIsShared() @@ -119,18 +120,21 @@ public void SimpleIntegerTest() var input = new CodedInputStream(stream); input.ReadTag(); - var options = CustomOptions.Empty; + var options = CustomOptions.Empty; options = options.ReadOrSkipUnknownField(input); + var typedFieldId1 = new MessageOptionFieldId(1); + var typedFieldId2 = new MessageOptionFieldId(2); + int intValue; - Assert.True(options.TryGetInt32(1, out intValue)); + Assert.True(options.TryGetInt32(typedFieldId1, out intValue)); Assert.AreEqual(1234567, intValue); string stringValue; // No ByteString stored values - Assert.False(options.TryGetString(1, out stringValue)); + Assert.False(options.TryGetString(typedFieldId1, out stringValue)); // Nothing stored for field 2 - Assert.False(options.TryGetInt32(2, out intValue)); + Assert.False(options.TryGetInt32(typedFieldId2, out intValue)); } [Test] @@ -145,109 +149,112 @@ public void SimpleStringTest() var input = new CodedInputStream(stream); input.ReadTag(); - var options = CustomOptions.Empty; + var options = CustomOptions.Empty; options = options.ReadOrSkipUnknownField(input); + var typedFieldId1 = new MessageOptionFieldId(1); + var typedFieldId2 = new MessageOptionFieldId(2); + string stringValue; - Assert.True(options.TryGetString(1, out stringValue)); + Assert.True(options.TryGetString(typedFieldId1, out stringValue)); Assert.AreEqual("value", stringValue); int intValue; // No numeric stored values - Assert.False(options.TryGetInt32(1, out intValue)); + Assert.False(options.TryGetInt32(typedFieldId1, out intValue)); // Nothing stored for field 2 - Assert.False(options.TryGetString(2, out stringValue)); + Assert.False(options.TryGetString(typedFieldId2, out stringValue)); } [Test] public void ScalarOptions() { var options = CustomOptionOtherValues.Descriptor.CustomOptions; - AssertOption(-100, options.TryGetInt32, Int32Opt); - AssertOption(12.3456789f, options.TryGetFloat, FloatOpt); - AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt); - AssertOption("Hello, \"World\"", options.TryGetString, StringOpt); - AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt); - AssertOption((int) TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt); + AssertOption(-100, options.TryGetInt32, Int32Opt); + AssertOption(12.3456789f, options.TryGetFloat, FloatOpt); + AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt); + AssertOption("Hello, \"World\"", options.TryGetString, StringOpt); + AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt); + AssertOption((int) TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt); } [Test] public void MessageOptions() { var options = VariousComplexOptions.Descriptor.CustomOptions; - AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1); - AssertOption(new ComplexOptionType2 + AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1); + AssertOption(new ComplexOptionType2 { Baz = 987, Bar = new ComplexOptionType1 { Foo = 743 }, Fred = new ComplexOptionType4 { Waldo = 321 }, Barney = { new ComplexOptionType4 { Waldo = 101 }, new ComplexOptionType4 { Waldo = 212 } } }, options.TryGetMessage, ComplexOpt2); - AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3); + AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3); } [Test] public void OptionLocations() { var fileOptions = UnittestCustomOptionsProto3Reflection.Descriptor.CustomOptions; - AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1); + AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1); var messageOptions = TestMessageWithCustomOptions.Descriptor.CustomOptions; - AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1); + AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1); - var fieldOptions = TestMessageWithCustomOptions.Descriptor.Fields["field1"] .CustomOptions; - AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1); + var fieldOptions = TestMessageWithCustomOptions.Descriptor.Fields["field1"].CustomOptions; + AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1); var oneofOptions = TestMessageWithCustomOptions.Descriptor.Oneofs[0].CustomOptions; - AssertOption(-99, oneofOptions.TryGetInt32, OneofOpt1); + AssertOption(-99, oneofOptions.TryGetInt32, OneofOpt1); var enumOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].CustomOptions; - AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1); + AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1); var enumValueOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].FindValueByNumber(2).CustomOptions; - AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1); + AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1); var service = UnittestCustomOptionsProto3Reflection.Descriptor.Services .Single(s => s.Name == "TestServiceWithCustomOptions"); var serviceOptions = service.CustomOptions; - AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1); + AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1); var methodOptions = service.Methods[0].CustomOptions; - AssertOption((int) UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1); + AssertOption((int) UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1); } [Test] public void MinValues() { var options = CustomOptionMinIntegerValues.Descriptor.CustomOptions; - AssertOption(false, options.TryGetBool, BoolOpt); - AssertOption(int.MinValue, options.TryGetInt32, Int32Opt); - AssertOption(long.MinValue, options.TryGetInt64, Int64Opt); - AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt); - AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt); - AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt); - AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt); - AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt); - AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt); - AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt); - AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt); + AssertOption(false, options.TryGetBool, BoolOpt); + AssertOption(int.MinValue, options.TryGetInt32, Int32Opt); + AssertOption(long.MinValue, options.TryGetInt64, Int64Opt); + AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt); + AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt); + AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt); + AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt); + AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt); + AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt); + AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt); + AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt); } [Test] public void MaxValues() { var options = CustomOptionMaxIntegerValues.Descriptor.CustomOptions; - AssertOption(true, options.TryGetBool, BoolOpt); - AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt); - AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt); - AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt); - AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt); - AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt); - AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt); - AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt); - AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt); - AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt); - AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt); + AssertOption(true, options.TryGetBool, BoolOpt); + AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt); + AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt); + AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt); + AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt); + AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt); + AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt); + AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt); + AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt); + AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt); + AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt); } [Test] @@ -255,16 +262,19 @@ public void AggregateOptions() { // Just two examples var messageOptions = AggregateMessage.Descriptor.CustomOptions; - AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt); + AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt); var fieldOptions = AggregateMessage.Descriptor.Fields["fieldname"].CustomOptions; - AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt); + AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt); } - private void AssertOption(T expected, OptionFetcher fetcher, CustomOptionNumber field) + private void AssertOption(T expected, OptionFetcher fetcher, CustomOptionNumber field) where FieldId : OptionFieldId { + // create an instance of the specific option id dynamically, normally this would be generated by the compiler + FieldId fid = (FieldId)Activator.CreateInstance(typeof(FieldId), (int)field); + T actual; - Assert.IsTrue(fetcher((int) field, out actual)); + Assert.IsTrue(fetcher(fid, out actual)); Assert.AreEqual(expected, actual); } } diff --git a/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs b/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs index 88b3ec000d315..b858656f6d7f9 100644 --- a/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs +++ b/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs @@ -57,12 +57,12 @@ namespace Google.Protobuf.Reflection /// all the set values are merged together. /// /// - public sealed class CustomOptions + public sealed class CustomOptions where FieldId : OptionFieldId { /// /// Singleton for all descriptors with an empty set of options. /// - internal static readonly CustomOptions Empty = new CustomOptions(); + internal static readonly CustomOptions Empty = new CustomOptions(); /// /// A sequence of values per field. This needs to be per field rather than per tag to allow correct deserialization @@ -79,9 +79,9 @@ private CustomOptions() { } /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetBool(int field, out bool value) + public bool TryGetBool(FieldId field, out bool value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = tmp == 1UL; return tmp != null; } @@ -92,9 +92,9 @@ public bool TryGetBool(int field, out bool value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetInt32(int field, out int value) + public bool TryGetInt32(FieldId field, out int value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = (int) tmp.GetValueOrDefault(); return tmp != null; } @@ -105,9 +105,9 @@ public bool TryGetInt32(int field, out int value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetInt64(int field, out long value) + public bool TryGetInt64(FieldId field, out long value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = (long) tmp.GetValueOrDefault(); return tmp != null; } @@ -119,7 +119,7 @@ public bool TryGetInt64(int field, out long value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetFixed32(int field, out uint value) => TryGetUInt32(field, out value); + public bool TryGetFixed32(FieldId field, out uint value) => TryGetUInt32(field, out value); /// /// Retrieves an unsigned 64-bit integer value for the specified option field, @@ -128,7 +128,7 @@ public bool TryGetInt64(int field, out long value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetFixed64(int field, out ulong value) => TryGetUInt64(field, out value); + public bool TryGetFixed64(FieldId field, out ulong value) => TryGetUInt64(field, out value); /// /// Retrieves a signed 32-bit integer value for the specified option field, @@ -137,7 +137,7 @@ public bool TryGetInt64(int field, out long value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetSFixed32(int field, out int value) => TryGetInt32(field, out value); + public bool TryGetSFixed32(FieldId field, out int value) => TryGetInt32(field, out value); /// /// Retrieves a signed 64-bit integer value for the specified option field, @@ -146,7 +146,7 @@ public bool TryGetInt64(int field, out long value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetSFixed64(int field, out long value) => TryGetInt64(field, out value); + public bool TryGetSFixed64(FieldId field, out long value) => TryGetInt64(field, out value); /// /// Retrieves a signed 32-bit integer value for the specified option field, @@ -155,9 +155,9 @@ public bool TryGetInt64(int field, out long value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetSInt32(int field, out int value) + public bool TryGetSInt32(FieldId field, out int value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = CodedInputStream.DecodeZigZag32((uint) tmp.GetValueOrDefault()); return tmp != null; } @@ -169,9 +169,9 @@ public bool TryGetSInt32(int field, out int value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetSInt64(int field, out long value) + public bool TryGetSInt64(FieldId field, out long value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = CodedInputStream.DecodeZigZag64(tmp.GetValueOrDefault()); return tmp != null; } @@ -182,9 +182,9 @@ public bool TryGetSInt64(int field, out long value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetUInt32(int field, out uint value) + public bool TryGetUInt32(FieldId field, out uint value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = (uint) tmp.GetValueOrDefault(); return tmp != null; } @@ -195,9 +195,9 @@ public bool TryGetUInt32(int field, out uint value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetUInt64(int field, out ulong value) + public bool TryGetUInt64(FieldId field, out ulong value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = tmp.GetValueOrDefault(); return tmp != null; } @@ -208,9 +208,9 @@ public bool TryGetUInt64(int field, out ulong value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetFloat(int field, out float value) + public bool TryGetFloat(FieldId field, out float value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); int int32 = (int) tmp.GetValueOrDefault(); byte[] bytes = BitConverter.GetBytes(int32); value = BitConverter.ToSingle(bytes, 0); @@ -223,9 +223,9 @@ public bool TryGetFloat(int field, out float value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetDouble(int field, out double value) + public bool TryGetDouble(FieldId field, out double value) { - ulong? tmp = GetLastNumericValue(field); + ulong? tmp = GetLastNumericValue(field.Id); value = BitConverter.Int64BitsToDouble((long) tmp.GetValueOrDefault()); return tmp != null; } @@ -236,9 +236,9 @@ public bool TryGetDouble(int field, out double value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetString(int field, out string value) + public bool TryGetString(FieldId field, out string value) { - ByteString bytes = GetLastByteStringValue(field); + ByteString bytes = GetLastByteStringValue(field.Id); value = bytes?.ToStringUtf8(); return bytes != null; } @@ -249,9 +249,9 @@ public bool TryGetString(int field, out string value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetBytes(int field, out ByteString value) + public bool TryGetBytes(FieldId field, out ByteString value) { - ByteString bytes = GetLastByteStringValue(field); + ByteString bytes = GetLastByteStringValue(field.Id); value = bytes; return bytes != null; } @@ -262,11 +262,11 @@ public bool TryGetBytes(int field, out ByteString value) /// The field to fetch the value for. /// The output variable to populate. /// true if a suitable value for the field was found; false otherwise. - public bool TryGetMessage(int field, out T value) where T : class, IMessage, new() + public bool TryGetMessage(FieldId field, out T value) where T : class, IMessage, new() { value = null; List values; - if (!valuesByField.TryGetValue(field, out values)) + if (!valuesByField.TryGetValue(field.Id, out values)) { return false; } @@ -329,7 +329,7 @@ private ByteString GetLastByteStringValue(int field) /// /// Input stream to read from. /// The resulting set of custom options, either this or a new set. - internal CustomOptions ReadOrSkipUnknownField(CodedInputStream input) + internal CustomOptions ReadOrSkipUnknownField(CodedInputStream input) { var tag = input.LastTag; var field = WireFormat.GetTagFieldNumber(tag); @@ -351,9 +351,9 @@ internal CustomOptions ReadOrSkipUnknownField(CodedInputStream input) } } - private CustomOptions AddValue(int field, FieldValue value) + private CustomOptions AddValue(int field, FieldValue value) { - var ret = valuesByField.Count == 0 ? new CustomOptions() : this; + var ret = valuesByField.Count == 0 ? new CustomOptions() : this; List valuesForField; if (!ret.valuesByField.TryGetValue(field, out valuesForField)) { @@ -387,4 +387,53 @@ internal FieldValue(ByteString byteString) } } } + + public abstract class OptionFieldId + { + public int Id { get; private set; } + + public OptionFieldId(int fieldId) + { + Id = fieldId; + } + } + + public class FileOptionFieldId : OptionFieldId + { + public FileOptionFieldId(int fieldId) : base(fieldId) { } + } + + public class MessageOptionFieldId : OptionFieldId + { + public MessageOptionFieldId(int fieldId) : base(fieldId) { } + } + + public class FieldOptionFieldId : OptionFieldId + { + public FieldOptionFieldId(int fieldId) : base(fieldId) { } + } + + public class EnumOptionFieldId : OptionFieldId + { + public EnumOptionFieldId(int fieldId) : base(fieldId) { } + } + + public class EnumValueOptionFieldId : OptionFieldId + { + public EnumValueOptionFieldId(int fieldId) : base(fieldId) { } + } + + public class ServiceOptionFieldId : OptionFieldId + { + public ServiceOptionFieldId(int fieldId) : base(fieldId) { } + } + public class MethodOptionFieldId : OptionFieldId + { + public MethodOptionFieldId(int fieldId) : base(fieldId) { } + } + + public class OneOfOptionFieldId : OptionFieldId + { + public OneOfOptionFieldId(int fieldId) : base(fieldId) { } + } } diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs index 0c33e63df46a9..7c14aaa2dc95c 100644 --- a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs @@ -3787,7 +3787,7 @@ internal sealed partial class FileOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FileOptions() { @@ -4847,7 +4847,7 @@ internal sealed partial class MessageOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public MessageOptions() { @@ -5193,7 +5193,7 @@ internal sealed partial class FieldOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FieldOptions() { @@ -5661,7 +5661,7 @@ internal sealed partial class OneofOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public OneofOptions() { @@ -5788,7 +5788,7 @@ internal sealed partial class EnumOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EnumOptions() { @@ -6008,7 +6008,7 @@ internal sealed partial class EnumValueOptions : pb::IMessage get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EnumValueOptions() { @@ -6183,7 +6183,7 @@ internal sealed partial class ServiceOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServiceOptions() { @@ -6358,7 +6358,7 @@ internal sealed partial class MethodOptions : pb::IMessage { get { return Descriptor; } } - internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; + internal CustomOptions CustomOptions{ get; private set; } = CustomOptions.Empty; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public MethodOptions() { diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs index 4c5457a70c724..9aaf220b00215 100644 --- a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs @@ -127,6 +127,6 @@ public EnumValueDescriptor FindValueByName(string name) /// /// The (possibly empty) set of custom options for this enum. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs index 8b838c68f0be9..5691712d3f847 100644 --- a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs @@ -70,6 +70,6 @@ internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file /// /// The (possibly empty) set of custom options for this enum value. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs index 0a46f9eb02aba..8602df50757ad 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs @@ -257,7 +257,7 @@ public MessageDescriptor MessageType /// /// The (possibly empty) set of custom options for this field. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; /// /// Look up and cross-link all field types etc. diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs index 6d4520c0bc045..e034c2d5f7c3f 100644 --- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs @@ -464,7 +464,7 @@ public override string ToString() /// /// The (possibly empty) set of custom options for this file. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; /// /// Performs initialization for the given generic type argument. diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs index 03fd63ce29b77..efcaf38b1e1e3 100644 --- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs @@ -236,7 +236,7 @@ public T FindDescriptor(string name) where T : class, IDescriptor => /// /// The (possibly empty) set of custom options for this message. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; /// /// Looks up and cross-links all fields and nested types. diff --git a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs index 19d7f8a09258f..56f2794969a74 100644 --- a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs @@ -70,7 +70,7 @@ public sealed class MethodDescriptor : DescriptorBase /// /// The (possibly empty) set of custom options for this method. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file, ServiceDescriptor parent, int index) diff --git a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs index c026bea6775d6..2e97990650083 100644 --- a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs @@ -103,7 +103,7 @@ public MessageDescriptor ContainingType /// /// The (possibly empty) set of custom options for this oneof. /// - public CustomOptions CustomOptions => proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => proto.Options?.CustomOptions ?? CustomOptions.Empty; internal void CrossLink() { diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs index da57055118a32..5964795fa1364 100644 --- a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs @@ -93,7 +93,7 @@ public MethodDescriptor FindMethodByName(String name) /// /// The (possibly empty) set of custom options for this service. /// - public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; + public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty; internal void CrossLink() { diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc index 5ddd616e10f59..ab32f293f0436 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -122,6 +122,65 @@ void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) { printer->Indent(); printer->Print("\n"); } + + printer->Print("public static class Extensions {\n"); + printer->Indent(); + for (int i = 0; i < file_->extension_count(); ++i) { + const FieldDescriptor& extension_field = *file_->extension(i); + + if (extension_field.containing_type()->full_name() == FileOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.FileOptionFieldId $var_name$ = new pbr.FileOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == MessageOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.MessageOptionFieldId $var_name$ = new pbr.MessageOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == FieldOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.FieldOptionFieldId $var_name$ = new pbr.FieldOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == EnumOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.EnumOptionFieldId $var_name$ = new pbr.EnumOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == EnumValueOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.EnumValueOptionFieldId $var_name$ = new pbr.EnumValueOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == ServiceOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.ServiceOptionFieldId $var_name$ = new pbr.ServiceOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == MethodOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.MethodOptionFieldId $var_name$ = new pbr.MethodOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + else if (extension_field.containing_type()->full_name() == OneofOptions::descriptor()->full_name()) + { + printer->Print("public static readonly pbr.OneOfOptionFieldId $var_name$ = new pbr.OneOfOptionFieldId($extension_id$);\n", + "var_name", extension_field.name(), + "extension_id", SimpleItoa(extension_field.number())); + } + } + printer->Outdent(); + printer->Print("}\n"); + + printer->Print( "/// Holder for reflection information generated from $file_name$\n" From 3cc09d967a014df10d6708b25f7bb65113a0a259 Mon Sep 17 00:00:00 2001 From: Jeremy Swigart Date: Wed, 10 Oct 2018 20:29:29 -0500 Subject: [PATCH 2/5] simple integer constant changed back to simple integer constant so compatibility isn't broken with the custom options api --- .../Reflection/CustomOptionsTest.cs | 115 ++++++++---------- .../Google.Protobuf/Google.Protobuf.csproj | 1 + .../Reflection/CustomOptions.cs | 115 +++++------------- .../Google.Protobuf/Reflection/Descriptor.cs | 16 +-- .../Reflection/EnumDescriptor.cs | 2 +- .../Reflection/EnumValueDescriptor.cs | 2 +- .../Reflection/FieldDescriptor.cs | 2 +- .../Reflection/FileDescriptor.cs | 2 +- .../Reflection/MessageDescriptor.cs | 2 +- .../Reflection/MethodDescriptor.cs | 2 +- .../Reflection/OneofDescriptor.cs | 2 +- .../Reflection/ServiceDescriptor.cs | 2 +- .../csharp/csharp_reflection_class.cc | 54 +------- 13 files changed, 108 insertions(+), 209 deletions(-) diff --git a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs index fca54e63dc27b..94cce39669778 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs @@ -120,21 +120,18 @@ public void SimpleIntegerTest() var input = new CodedInputStream(stream); input.ReadTag(); - var options = CustomOptions.Empty; + var options = CustomOptions.Empty; options = options.ReadOrSkipUnknownField(input); - - var typedFieldId1 = new MessageOptionFieldId(1); - var typedFieldId2 = new MessageOptionFieldId(2); - + int intValue; - Assert.True(options.TryGetInt32(typedFieldId1, out intValue)); + Assert.True(options.TryGetInt32(1, out intValue)); Assert.AreEqual(1234567, intValue); string stringValue; // No ByteString stored values - Assert.False(options.TryGetString(typedFieldId1, out stringValue)); + Assert.False(options.TryGetString(1, out stringValue)); // Nothing stored for field 2 - Assert.False(options.TryGetInt32(typedFieldId2, out intValue)); + Assert.False(options.TryGetInt32(2, out intValue)); } [Test] @@ -149,112 +146,109 @@ public void SimpleStringTest() var input = new CodedInputStream(stream); input.ReadTag(); - var options = CustomOptions.Empty; + var options = CustomOptions.Empty; options = options.ReadOrSkipUnknownField(input); - - var typedFieldId1 = new MessageOptionFieldId(1); - var typedFieldId2 = new MessageOptionFieldId(2); - + string stringValue; - Assert.True(options.TryGetString(typedFieldId1, out stringValue)); + Assert.True(options.TryGetString(1, out stringValue)); Assert.AreEqual("value", stringValue); int intValue; // No numeric stored values - Assert.False(options.TryGetInt32(typedFieldId1, out intValue)); + Assert.False(options.TryGetInt32(1, out intValue)); // Nothing stored for field 2 - Assert.False(options.TryGetString(typedFieldId2, out stringValue)); + Assert.False(options.TryGetString(2, out stringValue)); } [Test] public void ScalarOptions() { var options = CustomOptionOtherValues.Descriptor.CustomOptions; - AssertOption(-100, options.TryGetInt32, Int32Opt); - AssertOption(12.3456789f, options.TryGetFloat, FloatOpt); - AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt); - AssertOption("Hello, \"World\"", options.TryGetString, StringOpt); - AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt); - AssertOption((int) TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt); + AssertOption(-100, options.TryGetInt32, Int32Opt); + AssertOption(12.3456789f, options.TryGetFloat, FloatOpt); + AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt); + AssertOption("Hello, \"World\"", options.TryGetString, StringOpt); + AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt); + AssertOption((int) TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt); } [Test] public void MessageOptions() { var options = VariousComplexOptions.Descriptor.CustomOptions; - AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1); - AssertOption(new ComplexOptionType2 + AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1); + AssertOption(new ComplexOptionType2 { Baz = 987, Bar = new ComplexOptionType1 { Foo = 743 }, Fred = new ComplexOptionType4 { Waldo = 321 }, Barney = { new ComplexOptionType4 { Waldo = 101 }, new ComplexOptionType4 { Waldo = 212 } } }, options.TryGetMessage, ComplexOpt2); - AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3); + AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3); } [Test] public void OptionLocations() { var fileOptions = UnittestCustomOptionsProto3Reflection.Descriptor.CustomOptions; - AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1); + AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1); var messageOptions = TestMessageWithCustomOptions.Descriptor.CustomOptions; - AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1); + AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1); var fieldOptions = TestMessageWithCustomOptions.Descriptor.Fields["field1"].CustomOptions; - AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1); + AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1); var oneofOptions = TestMessageWithCustomOptions.Descriptor.Oneofs[0].CustomOptions; - AssertOption(-99, oneofOptions.TryGetInt32, OneofOpt1); + AssertOption(-99, oneofOptions.TryGetInt32, OneofOpt1); var enumOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].CustomOptions; - AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1); + AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1); var enumValueOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].FindValueByNumber(2).CustomOptions; - AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1); + AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1); var service = UnittestCustomOptionsProto3Reflection.Descriptor.Services .Single(s => s.Name == "TestServiceWithCustomOptions"); var serviceOptions = service.CustomOptions; - AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1); + AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1); var methodOptions = service.Methods[0].CustomOptions; - AssertOption((int) UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1); + AssertOption((int) UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1); } [Test] public void MinValues() { var options = CustomOptionMinIntegerValues.Descriptor.CustomOptions; - AssertOption(false, options.TryGetBool, BoolOpt); - AssertOption(int.MinValue, options.TryGetInt32, Int32Opt); - AssertOption(long.MinValue, options.TryGetInt64, Int64Opt); - AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt); - AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt); - AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt); - AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt); - AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt); - AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt); - AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt); - AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt); + AssertOption(false, options.TryGetBool, BoolOpt); + AssertOption(int.MinValue, options.TryGetInt32, Int32Opt); + AssertOption(long.MinValue, options.TryGetInt64, Int64Opt); + AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt); + AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt); + AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt); + AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt); + AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt); + AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt); + AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt); + AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt); } [Test] public void MaxValues() { var options = CustomOptionMaxIntegerValues.Descriptor.CustomOptions; - AssertOption(true, options.TryGetBool, BoolOpt); - AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt); - AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt); - AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt); - AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt); - AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt); - AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt); - AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt); - AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt); - AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt); - AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt); + AssertOption(true, options.TryGetBool, BoolOpt); + AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt); + AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt); + AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt); + AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt); + AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt); + AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt); + AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt); + AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt); + AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt); + AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt); } [Test] @@ -262,19 +256,16 @@ public void AggregateOptions() { // Just two examples var messageOptions = AggregateMessage.Descriptor.CustomOptions; - AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt); + AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt); var fieldOptions = AggregateMessage.Descriptor.Fields["fieldname"].CustomOptions; - AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt); + AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt); } - private void AssertOption(T expected, OptionFetcher fetcher, CustomOptionNumber field) where FieldId : OptionFieldId + private void AssertOption(T expected, OptionFetcher fetcher, CustomOptionNumber field) { - // create an instance of the specific option id dynamically, normally this would be generated by the compiler - FieldId fid = (FieldId)Activator.CreateInstance(typeof(FieldId), (int)field); - T actual; - Assert.IsTrue(fetcher(fid, out actual)); + Assert.IsTrue(fetcher((int)field, out actual)); Assert.AreEqual(expected, actual); } } diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 8ea3818a4a833..4767b77172735 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -17,6 +17,7 @@ https://github.com/protocolbuffers/protobuf/blob/master/LICENSE git https://github.com/protocolbuffers/protobuf.git + True