Commit 272d384f authored by Jon Skeet's avatar Jon Skeet

Use delegates instead of dynamic reflection.

parent db9d2fcd
...@@ -16,11 +16,15 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -16,11 +16,15 @@ namespace Google.ProtocolBuffers.TestProtos {
get { return defaultInstance; } get { return defaultInstance; }
} }
protected override MessageWithNoOuter ThisMessage {
get { return this; }
}
public static pbd::MessageDescriptor Descriptor { public static pbd::MessageDescriptor Descriptor {
get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor; } get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor; }
} }
protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { protected override pb::FieldAccess.FieldAccessorTable<MessageWithNoOuter, MessageWithNoOuter.Builder> InternalFieldAccessors {
get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter__FieldAccessorTable; } get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter__FieldAccessorTable; }
} }
...@@ -40,11 +44,15 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -40,11 +44,15 @@ namespace Google.ProtocolBuffers.TestProtos {
get { return defaultInstance; } get { return defaultInstance; }
} }
protected override NestedMessage ThisMessage {
get { return this; }
}
public static pbd::MessageDescriptor Descriptor { public static pbd::MessageDescriptor Descriptor {
get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__Descriptor; } get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__Descriptor; }
} }
protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { protected override pb::FieldAccess.FieldAccessorTable<NestedMessage, NestedMessage.Builder> InternalFieldAccessors {
get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__FieldAccessorTable; } get { return global::Google.ProtocolBuffers.TestProtos.MultiFileProto.internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__FieldAccessorTable; }
} }
......
...@@ -64,18 +64,14 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -64,18 +64,14 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Static variables #region Static variables
internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor
= Descriptor.MessageTypes[0]; = Descriptor.MessageTypes[0];
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_MessageWithNoOuter__FieldAccessorTable internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter, global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Builder> internal__static_protobuf_unittest_MessageWithNoOuter__FieldAccessorTable
= new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor, = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter, global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Builder>(internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor,
new string[] { "Nested", "Foreign", "NestedEnum", "ForeignEnum", }, new string[] { "Nested", "Foreign", "NestedEnum", "ForeignEnum", });
typeof (global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter),
typeof (global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Builder));
internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__Descriptor internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__Descriptor
= internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor.NestedTypes[0]; = internal__static_protobuf_unittest_MessageWithNoOuter__Descriptor.NestedTypes[0];
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__FieldAccessorTable internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Types.NestedMessage, global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Types.NestedMessage.Builder> internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__FieldAccessorTable
= new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__Descriptor, = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Types.NestedMessage, global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Types.NestedMessage.Builder>(internal__static_protobuf_unittest_MessageWithNoOuter_NestedMessage__Descriptor,
new string[] { "I", }, new string[] { "I", });
typeof (global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Types.NestedMessage),
typeof (global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter.Types.NestedMessage.Builder));
#endregion #endregion
} }
......
...@@ -43,11 +43,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -43,11 +43,9 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Static variables #region Static variables
internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestEmbedOptimizedForSize__Descriptor internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestEmbedOptimizedForSize__Descriptor
= Descriptor.MessageTypes[0]; = Descriptor.MessageTypes[0];
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_TestEmbedOptimizedForSize__FieldAccessorTable internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize.Builder> internal__static_protobuf_unittest_TestEmbedOptimizedForSize__FieldAccessorTable
= new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_TestEmbedOptimizedForSize__Descriptor, = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize.Builder>(internal__static_protobuf_unittest_TestEmbedOptimizedForSize__Descriptor,
new string[] { "OptionalMessage", "RepeatedMessage", }, new string[] { "OptionalMessage", "RepeatedMessage", });
typeof (global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize),
typeof (global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize.Builder));
#endregion #endregion
} }
...@@ -66,11 +64,15 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -66,11 +64,15 @@ namespace Google.ProtocolBuffers.TestProtos {
get { return defaultInstance; } get { return defaultInstance; }
} }
protected override TestEmbedOptimizedForSize ThisMessage {
get { return this; }
}
public static pbd::MessageDescriptor Descriptor { public static pbd::MessageDescriptor Descriptor {
get { return global::Google.ProtocolBuffers.TestProtos.UnitTestEmbedOptimizeForProtoFile.internal__static_protobuf_unittest_TestEmbedOptimizedForSize__Descriptor; } get { return global::Google.ProtocolBuffers.TestProtos.UnitTestEmbedOptimizeForProtoFile.internal__static_protobuf_unittest_TestEmbedOptimizedForSize__Descriptor; }
} }
protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { protected override pb::FieldAccess.FieldAccessorTable<TestEmbedOptimizedForSize, TestEmbedOptimizedForSize.Builder> InternalFieldAccessors {
get { return global::Google.ProtocolBuffers.TestProtos.UnitTestEmbedOptimizeForProtoFile.internal__static_protobuf_unittest_TestEmbedOptimizedForSize__FieldAccessorTable; } get { return global::Google.ProtocolBuffers.TestProtos.UnitTestEmbedOptimizeForProtoFile.internal__static_protobuf_unittest_TestEmbedOptimizedForSize__FieldAccessorTable; }
} }
......
...@@ -37,11 +37,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -37,11 +37,9 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Static variables #region Static variables
internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_import_ImportMessage__Descriptor internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_import_ImportMessage__Descriptor
= Descriptor.MessageTypes[0]; = Descriptor.MessageTypes[0];
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.ImportMessage, global::Google.ProtocolBuffers.TestProtos.ImportMessage.Builder> internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable
= new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_import_ImportMessage__Descriptor, = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.ImportMessage, global::Google.ProtocolBuffers.TestProtos.ImportMessage.Builder>(internal__static_protobuf_unittest_import_ImportMessage__Descriptor,
new string[] { "D", }, new string[] { "D", });
typeof (global::Google.ProtocolBuffers.TestProtos.ImportMessage),
typeof (global::Google.ProtocolBuffers.TestProtos.ImportMessage.Builder));
#endregion #endregion
} }
...@@ -66,11 +64,15 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -66,11 +64,15 @@ namespace Google.ProtocolBuffers.TestProtos {
get { return defaultInstance; } get { return defaultInstance; }
} }
protected override ImportMessage ThisMessage {
get { return this; }
}
public static pbd::MessageDescriptor Descriptor { public static pbd::MessageDescriptor Descriptor {
get { return global::Google.ProtocolBuffers.TestProtos.UnitTestImportProtoFile.internal__static_protobuf_unittest_import_ImportMessage__Descriptor; } get { return global::Google.ProtocolBuffers.TestProtos.UnitTestImportProtoFile.internal__static_protobuf_unittest_import_ImportMessage__Descriptor; }
} }
protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { protected override pb::FieldAccess.FieldAccessorTable<ImportMessage, ImportMessage.Builder> InternalFieldAccessors {
get { return global::Google.ProtocolBuffers.TestProtos.UnitTestImportProtoFile.internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable; } get { return global::Google.ProtocolBuffers.TestProtos.UnitTestImportProtoFile.internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable; }
} }
......
...@@ -42,11 +42,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -42,11 +42,9 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Static variables #region Static variables
internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor
= Descriptor.MessageTypes[0]; = Descriptor.MessageTypes[0];
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_TestOptimizedForSize__FieldAccessorTable internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder> internal__static_protobuf_unittest_TestOptimizedForSize__FieldAccessorTable
= new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor, = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder>(internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor,
new string[] { "I", "Msg", }, new string[] { "I", "Msg", });
typeof (global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize),
typeof (global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder));
#endregion #endregion
} }
...@@ -65,11 +63,15 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -65,11 +63,15 @@ namespace Google.ProtocolBuffers.TestProtos {
get { return defaultInstance; } get { return defaultInstance; }
} }
protected override TestOptimizedForSize ThisMessage {
get { return this; }
}
public static pbd::MessageDescriptor Descriptor { public static pbd::MessageDescriptor Descriptor {
get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor; } get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor; }
} }
protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { protected override pb::FieldAccess.FieldAccessorTable<TestOptimizedForSize, TestOptimizedForSize.Builder> InternalFieldAccessors {
get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestOptimizedForSize__FieldAccessorTable; } get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestOptimizedForSize__FieldAccessorTable; }
} }
......
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers.FieldAccess {
delegate bool HasDelegate<T>(T message);
delegate T ClearDelegate<T>(T builder);
delegate int RepeatedCountDelegate<T>(T message);
delegate object GetValueDelegate<T>(T message);
}
...@@ -23,9 +23,11 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -23,9 +23,11 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// create appropriate instances in the .proto file description class. /// create appropriate instances in the .proto file description class.
/// TODO(jonskeet): See if we can hide it somewhere... /// TODO(jonskeet): See if we can hide it somewhere...
/// </summary> /// </summary>
public sealed class FieldAccessorTable { public sealed class FieldAccessorTable<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
readonly IFieldAccessor[] accessors; readonly IFieldAccessor<TMessage, TBuilder>[] accessors;
readonly MessageDescriptor descriptor; readonly MessageDescriptor descriptor;
...@@ -39,36 +41,34 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -39,36 +41,34 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// </summary> /// </summary>
/// <param name="descriptor">The type's descriptor</param> /// <param name="descriptor">The type's descriptor</param>
/// <param name="propertyNames">The Pascal-case names of all the field-based properties in the message.</param> /// <param name="propertyNames">The Pascal-case names of all the field-based properties in the message.</param>
/// <param name="messageType">The .NET type representing the message</param> public FieldAccessorTable(MessageDescriptor descriptor, String[] propertyNames) {
/// <param name="builderType">The .NET type representing the message's builder type</param>
public FieldAccessorTable(MessageDescriptor descriptor, String[] propertyNames, Type messageType, Type builderType) {
this.descriptor = descriptor; this.descriptor = descriptor;
accessors = new IFieldAccessor[descriptor.Fields.Count]; accessors = new IFieldAccessor<TMessage, TBuilder>[descriptor.Fields.Count];
for (int i=0; i < accessors.Length; i++) { for (int i=0; i < accessors.Length; i++) {
accessors[i] = CreateAccessor(descriptor.Fields[i], propertyNames[i], messageType, builderType); accessors[i] = CreateAccessor(descriptor.Fields[i], propertyNames[i]);
} }
} }
/// <summary> /// <summary>
/// Creates an accessor for a single field /// Creates an accessor for a single field
/// </summary> /// </summary>
private static IFieldAccessor CreateAccessor(FieldDescriptor field, string name, Type messageType, Type builderType) { private static IFieldAccessor<TMessage, TBuilder> CreateAccessor(FieldDescriptor field, string name) {
if (field.IsRepeated) { if (field.IsRepeated) {
switch (field.MappedType) { switch (field.MappedType) {
case MappedType.Message: return new RepeatedMessageAccessor(name, messageType, builderType); case MappedType.Message: return new RepeatedMessageAccessor<TMessage, TBuilder>(name);
case MappedType.Enum: return new RepeatedEnumAccessor(field, name, messageType, builderType); case MappedType.Enum: return new RepeatedEnumAccessor<TMessage, TBuilder>(field, name);
default: return new RepeatedPrimitiveAccessor(name, messageType, builderType); default: return new RepeatedPrimitiveAccessor<TMessage, TBuilder>(name);
} }
} else { } else {
switch (field.MappedType) { switch (field.MappedType) {
case MappedType.Message: return new SingleMessageAccessor(name, messageType, builderType); case MappedType.Message: return new SingleMessageAccessor<TMessage, TBuilder>(name);
case MappedType.Enum: return new SingleEnumAccessor(field, name, messageType, builderType); case MappedType.Enum: return new SingleEnumAccessor<TMessage, TBuilder>(field, name);
default: return new SinglePrimitiveAccessor(name, messageType, builderType); default: return new SinglePrimitiveAccessor<TMessage, TBuilder>(name);
} }
} }
} }
internal IFieldAccessor this[FieldDescriptor field] { internal IFieldAccessor<TMessage, TBuilder> this[FieldDescriptor field] {
get { get {
if (field.ContainingType != descriptor) { if (field.ContainingType != descriptor) {
throw new ArgumentException("FieldDescriptor does not match message type."); throw new ArgumentException("FieldDescriptor does not match message type.");
......
...@@ -21,23 +21,25 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -21,23 +21,25 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// The property descriptors for each field are created once and then cached. /// The property descriptors for each field are created once and then cached.
/// In addition, this interface holds knowledge of repeated fields, builders etc. /// In addition, this interface holds knowledge of repeated fields, builders etc.
/// </summary> /// </summary>
internal interface IFieldAccessor { internal interface IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
/// <summary> /// <summary>
/// Indicates whether the specified message contains the field. /// Indicates whether the specified message contains the field.
/// </summary> /// </summary>
bool Has(IMessage message); bool Has(TMessage message);
/// <summary> /// <summary>
/// Gets the count of the repeated field in the specified message. /// Gets the count of the repeated field in the specified message.
/// </summary> /// </summary>
int GetRepeatedCount(IMessage message); int GetRepeatedCount(TMessage message);
/// <summary> /// <summary>
/// Clears the field in the specified builder. /// Clears the field in the specified builder.
/// </summary> /// </summary>
/// <param name="builder"></param> /// <param name="builder"></param>
void Clear(IBuilder builder); void Clear(TBuilder builder);
/// <summary> /// <summary>
/// Creates a builder for the type of this field (which must be a message field). /// Creates a builder for the type of this field (which must be a message field).
...@@ -47,11 +49,11 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -47,11 +49,11 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Accessor for single fields /// Accessor for single fields
/// </summary> /// </summary>
object GetValue(IMessage message); object GetValue(TMessage message);
/// <summary> /// <summary>
/// Mutator for single fields /// Mutator for single fields
/// </summary> /// </summary>
void SetValue(IBuilder builder, object value); void SetValue(TBuilder builder, object value);
/// <summary> /// <summary>
/// Accessor for repeated fields /// Accessor for repeated fields
......
...@@ -24,17 +24,17 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -24,17 +24,17 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Accessor for a repeated enum field. /// Accessor for a repeated enum field.
/// </summary> /// </summary>
internal sealed class RepeatedEnumAccessor : RepeatedPrimitiveAccessor { internal sealed class RepeatedEnumAccessor<TMessage, TBuilder> : RepeatedPrimitiveAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
private readonly EnumDescriptor enumDescriptor; private readonly EnumDescriptor enumDescriptor;
internal RepeatedEnumAccessor(FieldDescriptor field, string name, Type messageType, Type builderType) internal RepeatedEnumAccessor(FieldDescriptor field, string name) : base(name) {
: base(name, messageType, builderType) {
enumDescriptor = field.EnumType; enumDescriptor = field.EnumType;
} }
public override object GetValue(IMessage message) { public override object GetValue(TMessage message) {
List<EnumValueDescriptor> ret = new List<EnumValueDescriptor>(); List<EnumValueDescriptor> ret = new List<EnumValueDescriptor>();
foreach (int rawValue in (IEnumerable) base.GetValue(message)) { foreach (int rawValue in (IEnumerable) base.GetValue(message)) {
ret.Add(enumDescriptor.FindValueByNumber(rawValue)); ret.Add(enumDescriptor.FindValueByNumber(rawValue));
......
...@@ -24,7 +24,9 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -24,7 +24,9 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// TODO(jonskeet): Try to extract the commonality between this and SingleMessageAccessor. /// TODO(jonskeet): Try to extract the commonality between this and SingleMessageAccessor.
/// We almost want multiple inheritance... /// We almost want multiple inheritance...
/// </summary> /// </summary>
internal sealed class RepeatedMessageAccessor : RepeatedPrimitiveAccessor { internal sealed class RepeatedMessageAccessor<TMessage, TBuilder> : RepeatedPrimitiveAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
/// <summary> /// <summary>
/// The static method to create a builder for the property type. For example, /// The static method to create a builder for the property type. For example,
...@@ -33,8 +35,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -33,8 +35,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// </summary> /// </summary>
private readonly MethodInfo createBuilderMethod; private readonly MethodInfo createBuilderMethod;
internal RepeatedMessageAccessor(string name, Type messageType, Type builderType) internal RepeatedMessageAccessor(string name) : base(name) {
: base(name, messageType, builderType) {
createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]);
if (createBuilderMethod == null) { if (createBuilderMethod == null) {
throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name); throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name);
......
...@@ -21,12 +21,14 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -21,12 +21,14 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Accesor for a repeated field of type int, ByteString etc. /// Accesor for a repeated field of type int, ByteString etc.
/// </summary> /// </summary>
internal class RepeatedPrimitiveAccessor : IFieldAccessor { internal class RepeatedPrimitiveAccessor<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
private readonly PropertyInfo messageProperty; private readonly PropertyInfo messageProperty;
private readonly PropertyInfo builderProperty; private readonly PropertyInfo builderProperty;
private readonly PropertyInfo countProperty; private readonly RepeatedCountDelegate<TMessage> countDelegate;
private readonly MethodInfo clearMethod; private readonly ClearDelegate<TBuilder> clearDelegate;
private readonly MethodInfo addMethod; private readonly MethodInfo addMethod;
private readonly MethodInfo getElementMethod; private readonly MethodInfo getElementMethod;
private readonly MethodInfo setElementMethod; private readonly MethodInfo setElementMethod;
...@@ -40,14 +42,14 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -40,14 +42,14 @@ namespace Google.ProtocolBuffers.FieldAccess {
get { return getElementMethod.ReturnType; } get { return getElementMethod.ReturnType; }
} }
internal RepeatedPrimitiveAccessor(string name, Type messageType, Type builderType) { internal RepeatedPrimitiveAccessor(string name) {
messageProperty = messageType.GetProperty(name + "List"); messageProperty = typeof(TMessage).GetProperty(name + "List");
builderProperty = builderType.GetProperty(name + "List"); builderProperty = typeof(TBuilder).GetProperty(name + "List");
countProperty = messageType.GetProperty(name + "Count"); PropertyInfo countProperty = typeof(TMessage).GetProperty(name + "Count");
clearMethod = builderType.GetMethod("Clear" + name); MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
getElementMethod = messageType.GetMethod("Get" + name, new Type[] { typeof(int) }); getElementMethod = typeof(TMessage).GetMethod("Get" + name, new Type[] { typeof(int) });
addMethod = builderType.GetMethod("Add" + name, new Type[] { ClrType }); addMethod = typeof(TBuilder).GetMethod("Add" + name, new Type[] { ClrType });
setElementMethod = builderType.GetMethod("Set" + name, new Type[] { typeof(int), ClrType }); setElementMethod = typeof(TBuilder).GetMethod("Set" + name, new Type[] { typeof(int), ClrType });
if (messageProperty == null if (messageProperty == null
|| builderProperty == null || builderProperty == null
|| countProperty == null || countProperty == null
...@@ -57,9 +59,12 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -57,9 +59,12 @@ namespace Google.ProtocolBuffers.FieldAccess {
|| setElementMethod == null) { || setElementMethod == null) {
throw new ArgumentException("Not all required properties/methods available"); throw new ArgumentException("Not all required properties/methods available");
} }
clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod);
countDelegate = (RepeatedCountDelegate<TMessage>)Delegate.CreateDelegate
(typeof(RepeatedCountDelegate<TMessage>), countProperty.GetGetMethod());
} }
public bool Has(IMessage message) { public bool Has(TMessage message) {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
...@@ -67,11 +72,11 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -67,11 +72,11 @@ namespace Google.ProtocolBuffers.FieldAccess {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public virtual object GetValue(IMessage message) { public virtual object GetValue(TMessage message) {
return messageProperty.GetValue(message, null); return messageProperty.GetValue(message, null);
} }
public void SetValue(IBuilder builder, object value) { public void SetValue(TBuilder builder, object value) {
// Add all the elements individually. This serves two purposes: // Add all the elements individually. This serves two purposes:
// 1) Verifies that each element has the correct type. // 1) Verifies that each element has the correct type.
// 2) Insures that the caller cannot modify the list later on and // 2) Insures that the caller cannot modify the list later on and
...@@ -82,12 +87,12 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -82,12 +87,12 @@ namespace Google.ProtocolBuffers.FieldAccess {
} }
} }
public void Clear(IBuilder builder) { public void Clear(TBuilder builder) {
clearMethod.Invoke(builder, null); clearDelegate(builder);
} }
public int GetRepeatedCount(IMessage message) { public int GetRepeatedCount(TMessage message) {
return (int) countProperty.GetValue(message, null); return countDelegate(message);
} }
public virtual object GetRepeatedValue(IMessage message, int index) { public virtual object GetRepeatedValue(IMessage message, int index) {
......
...@@ -20,12 +20,13 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -20,12 +20,13 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Accessor for fields representing a non-repeated enum value. /// Accessor for fields representing a non-repeated enum value.
/// </summary> /// </summary>
internal sealed class SingleEnumAccessor : SinglePrimitiveAccessor { internal sealed class SingleEnumAccessor<TMessage, TBuilder> : SinglePrimitiveAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
private readonly EnumDescriptor enumDescriptor; private readonly EnumDescriptor enumDescriptor;
internal SingleEnumAccessor(FieldDescriptor field, string name, Type messageType, Type builderType) internal SingleEnumAccessor(FieldDescriptor field, string name) : base(name) {
: base(name, messageType, builderType) {
enumDescriptor = field.EnumType; enumDescriptor = field.EnumType;
} }
...@@ -34,7 +35,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -34,7 +35,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// Note that if an enum has multiple values for the same number, the descriptor /// Note that if an enum has multiple values for the same number, the descriptor
/// for the first value with that number will be returned. /// for the first value with that number will be returned.
/// </summary> /// </summary>
public override object GetValue(IMessage message) { public override object GetValue(TMessage message) {
// Note: This relies on the fact that the CLR allows unboxing from an enum to // Note: This relies on the fact that the CLR allows unboxing from an enum to
// its underlying value // its underlying value
int rawValue = (int) base.GetValue(message); int rawValue = (int) base.GetValue(message);
...@@ -45,7 +46,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -45,7 +46,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// Sets the value as an enum (via an int) in the builder, /// Sets the value as an enum (via an int) in the builder,
/// from an EnumValueDescriptor parameter. /// from an EnumValueDescriptor parameter.
/// </summary> /// </summary>
public override void SetValue(IBuilder builder, object value) { public override void SetValue(TBuilder builder, object value) {
EnumValueDescriptor valueDescriptor = (EnumValueDescriptor) value; EnumValueDescriptor valueDescriptor = (EnumValueDescriptor) value;
base.SetValue(builder, valueDescriptor.Number); base.SetValue(builder, valueDescriptor.Number);
} }
......
...@@ -20,7 +20,9 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -20,7 +20,9 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Accessor for fields representing a non-repeated message value. /// Accessor for fields representing a non-repeated message value.
/// </summary> /// </summary>
internal sealed class SingleMessageAccessor : SinglePrimitiveAccessor { internal sealed class SingleMessageAccessor<TMessage, TBuilder> : SinglePrimitiveAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
/// <summary> /// <summary>
/// The static method to create a builder for the property type. For example, /// The static method to create a builder for the property type. For example,
...@@ -30,8 +32,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -30,8 +32,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
private readonly MethodInfo createBuilderMethod; private readonly MethodInfo createBuilderMethod;
internal SingleMessageAccessor(string name, Type messageType, Type builderType) internal SingleMessageAccessor(string name) : base(name) {
: base(name, messageType, builderType) {
createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]);//BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]);//BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
if (createBuilderMethod == null) { if (createBuilderMethod == null) {
...@@ -55,7 +56,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -55,7 +56,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
return CreateBuilder().WeakMergeFrom(message).WeakBuild(); return CreateBuilder().WeakMergeFrom(message).WeakBuild();
} }
public override void SetValue(IBuilder builder, object value) { public override void SetValue(TBuilder builder, object value) {
base.SetValue(builder, CoerceType(value)); base.SetValue(builder, CoerceType(value));
} }
......
...@@ -20,12 +20,14 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -20,12 +20,14 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Access for a non-repeated field of a "primitive" type (i.e. not another message or an enum). /// Access for a non-repeated field of a "primitive" type (i.e. not another message or an enum).
/// </summary> /// </summary>
internal class SinglePrimitiveAccessor : IFieldAccessor { internal class SinglePrimitiveAccessor<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> {
private readonly PropertyInfo messageProperty; private readonly PropertyInfo messageProperty;
private readonly PropertyInfo builderProperty; private readonly PropertyInfo builderProperty;
private readonly PropertyInfo hasProperty; private readonly HasDelegate<TMessage> hasDelegate;
private readonly MethodInfo clearMethod; private readonly ClearDelegate<TBuilder> clearDelegate;
/// <summary> /// <summary>
/// The CLR type of the field (int, the enum type, ByteString, the message etc). /// The CLR type of the field (int, the enum type, ByteString, the message etc).
...@@ -35,22 +37,24 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -35,22 +37,24 @@ namespace Google.ProtocolBuffers.FieldAccess {
get { return messageProperty.PropertyType; } get { return messageProperty.PropertyType; }
} }
internal SinglePrimitiveAccessor(string name, Type messageType, Type builderType) { internal SinglePrimitiveAccessor(string name) {
messageProperty = messageType.GetProperty(name); messageProperty = typeof(TMessage).GetProperty(name);
builderProperty = builderType.GetProperty(name); builderProperty = typeof(TBuilder).GetProperty(name);
hasProperty = messageType.GetProperty("Has" + name); PropertyInfo hasProperty = typeof(TMessage).GetProperty("Has" + name);
clearMethod = builderType.GetMethod("Clear" + name); MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
if (messageProperty == null || builderProperty == null || hasProperty == null || clearMethod == null) { if (messageProperty == null || builderProperty == null || hasProperty == null || clearMethod == null) {
throw new ArgumentException("Not all required properties/methods available"); throw new ArgumentException("Not all required properties/methods available");
} }
hasDelegate = (HasDelegate<TMessage>)Delegate.CreateDelegate(typeof(HasDelegate<TMessage>), hasProperty.GetGetMethod());
clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod);
} }
public bool Has(IMessage message) { public bool Has(TMessage message) {
return (bool) hasProperty.GetValue(message, null); return hasDelegate(message);
} }
public void Clear(IBuilder builder) { public void Clear(TBuilder builder) {
clearMethod.Invoke(builder, null); clearDelegate(builder);
} }
/// <summary> /// <summary>
...@@ -60,16 +64,16 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -60,16 +64,16 @@ namespace Google.ProtocolBuffers.FieldAccess {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public virtual object GetValue(IMessage message) { public virtual object GetValue(TMessage message) {
return messageProperty.GetValue(message, null); return messageProperty.GetValue(message, null);
} }
public virtual void SetValue(IBuilder builder, object value) { public virtual void SetValue(TBuilder builder, object value) {
builderProperty.SetValue(builder, value, null); builderProperty.SetValue(builder, value, null);
} }
#region Methods only related to repeated values #region Methods only related to repeated values
public int GetRepeatedCount(IMessage message) { public int GetRepeatedCount(TMessage message) {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
......
...@@ -34,8 +34,8 @@ namespace Google.ProtocolBuffers { ...@@ -34,8 +34,8 @@ namespace Google.ProtocolBuffers {
/// </summary> /// </summary>
protected abstract TMessage MessageBeingBuilt { get; } protected abstract TMessage MessageBeingBuilt { get; }
protected internal FieldAccessorTable InternalFieldAccessors { protected internal FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors {
get { return MessageBeingBuilt.FieldAccesseorsFromBuilder; } get { return MessageBeingBuilt.FieldAccessorsFromBuilder; }
} }
public override bool IsInitialized { public override bool IsInitialized {
...@@ -104,7 +104,7 @@ namespace Google.ProtocolBuffers { ...@@ -104,7 +104,7 @@ namespace Google.ProtocolBuffers {
} }
public override TBuilder ClearField(FieldDescriptor field) { public override TBuilder ClearField(FieldDescriptor field) {
InternalFieldAccessors[field].Clear(this); InternalFieldAccessors[field].Clear(ThisBuilder);
return ThisBuilder; return ThisBuilder;
} }
......
...@@ -33,11 +33,16 @@ namespace Google.ProtocolBuffers { ...@@ -33,11 +33,16 @@ namespace Google.ProtocolBuffers {
private UnknownFieldSet unknownFields = UnknownFieldSet.DefaultInstance; private UnknownFieldSet unknownFields = UnknownFieldSet.DefaultInstance;
internal FieldAccessorTable FieldAccesseorsFromBuilder { /// <summary>
/// Returns the message as a TMessage.
/// </summary>
protected abstract TMessage ThisMessage { get; }
internal FieldAccessorTable<TMessage, TBuilder> FieldAccessorsFromBuilder {
get { return InternalFieldAccessors; } get { return InternalFieldAccessors; }
} }
protected abstract FieldAccessorTable InternalFieldAccessors { get; } protected abstract FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors { get; }
public override MessageDescriptor DescriptorForType { public override MessageDescriptor DescriptorForType {
get { return InternalFieldAccessors.Descriptor; } get { return InternalFieldAccessors.Descriptor; }
...@@ -49,13 +54,13 @@ namespace Google.ProtocolBuffers { ...@@ -49,13 +54,13 @@ namespace Google.ProtocolBuffers {
var ret = new SortedList<FieldDescriptor, object>(); var ret = new SortedList<FieldDescriptor, object>();
MessageDescriptor descriptor = DescriptorForType; MessageDescriptor descriptor = DescriptorForType;
foreach (FieldDescriptor field in descriptor.Fields) { foreach (FieldDescriptor field in descriptor.Fields) {
IFieldAccessor accessor = InternalFieldAccessors[field]; IFieldAccessor<TMessage, TBuilder> accessor = InternalFieldAccessors[field];
if (field.IsRepeated) { if (field.IsRepeated) {
if (accessor.GetRepeatedCount(this) != 0) { if (accessor.GetRepeatedCount(ThisMessage) != 0) {
ret[field] = accessor.GetValue(this); ret[field] = accessor.GetValue(ThisMessage);
} }
} else if (HasField(field)) { } else if (HasField(field)) {
ret[field] = accessor.GetValue(this); ret[field] = accessor.GetValue(ThisMessage);
} }
} }
return ret; return ret;
...@@ -99,11 +104,11 @@ namespace Google.ProtocolBuffers { ...@@ -99,11 +104,11 @@ namespace Google.ProtocolBuffers {
} }
public override bool HasField(FieldDescriptor field) { public override bool HasField(FieldDescriptor field) {
return InternalFieldAccessors[field].Has(this); return InternalFieldAccessors[field].Has(ThisMessage);
} }
public override int GetRepeatedFieldCount(FieldDescriptor field) { public override int GetRepeatedFieldCount(FieldDescriptor field) {
return InternalFieldAccessors[field].GetRepeatedCount(this); return InternalFieldAccessors[field].GetRepeatedCount(ThisMessage);
} }
public override object this[FieldDescriptor field, int index] { public override object this[FieldDescriptor field, int index] {
...@@ -111,7 +116,7 @@ namespace Google.ProtocolBuffers { ...@@ -111,7 +116,7 @@ namespace Google.ProtocolBuffers {
} }
public override object this[FieldDescriptor field] { public override object this[FieldDescriptor field] {
get { return InternalFieldAccessors[field].GetValue(this); } get { return InternalFieldAccessors[field].GetValue(ThisMessage); }
} }
public override UnknownFieldSet UnknownFields { public override UnknownFieldSet UnknownFields {
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AbstractBuilder.cs" /> <Compile Include="AbstractBuilder.cs" />
...@@ -69,6 +71,7 @@ ...@@ -69,6 +71,7 @@
<Compile Include="ExtendableMessage.cs" /> <Compile Include="ExtendableMessage.cs" />
<Compile Include="ExtensionInfo.cs" /> <Compile Include="ExtensionInfo.cs" />
<Compile Include="ExtensionRegistry.cs" /> <Compile Include="ExtensionRegistry.cs" />
<Compile Include="FieldAccess\Delegates.cs" />
<Compile Include="FieldAccess\SingleEnumAccessor.cs" /> <Compile Include="FieldAccess\SingleEnumAccessor.cs" />
<Compile Include="FieldAccess\SingleMessageAccessor.cs" /> <Compile Include="FieldAccess\SingleMessageAccessor.cs" />
<Compile Include="FieldAccess\SinglePrimitiveAccessor.cs" /> <Compile Include="FieldAccess\SinglePrimitiveAccessor.cs" />
......
...@@ -175,8 +175,8 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { ...@@ -175,8 +175,8 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
// And the FieldAccessorTable. // And the FieldAccessorTable.
printer->Print(vars, printer->Print(vars,
"$private$static pb::FieldAccess.FieldAccessorTable internal__$identifier$__FieldAccessorTable\r\n" "$private$static pb::FieldAccess.FieldAccessorTable<$classname$, $classname$.Builder> internal__$identifier$__FieldAccessorTable\r\n"
" = new pb::FieldAccess.FieldAccessorTable(internal__$identifier$__Descriptor,\r\n" " = new pb::FieldAccess.FieldAccessorTable<$classname$, $classname$.Builder>(internal__$identifier$__Descriptor,\r\n"
" new string[] { "); " new string[] { ");
for (int i = 0; i < descriptor_->field_count(); i++) { for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print( printer->Print(
...@@ -184,10 +184,7 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { ...@@ -184,10 +184,7 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
"field_name", "field_name",
UnderscoresToCapitalizedCamelCase(descriptor_->field(i))); UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
} }
printer->Print("},\r\n" printer->Print("});\r\n");
" typeof ($classname$),\r\n"
" typeof ($classname$.Builder));\r\n",
"classname", ClassName(descriptor_));
// Generate static members for all nested types. // Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) { for (int i = 0; i < descriptor_->nested_type_count(); i++) {
...@@ -225,17 +222,26 @@ void MessageGenerator::Generate(io::Printer* printer) { ...@@ -225,17 +222,26 @@ void MessageGenerator::Generate(io::Printer* printer) {
"}\r\n" "}\r\n"
"\r\n", "\r\n",
"classname", descriptor_->name()); "classname", descriptor_->name());
printer->Print( printer->Print(
"protected override $classname$ ThisMessage {\r\n"
" get { return this; }\r\n"
"}\r\n\r\n",
"classname", descriptor_->name());
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["fileclass"] = ClassName(descriptor_->file());
vars["classname"] = descriptor_->name();
printer->Print(vars,
"public static pbd::MessageDescriptor Descriptor {\r\n" "public static pbd::MessageDescriptor Descriptor {\r\n"
" get { return $fileclass$.internal__$identifier$__Descriptor; }\r\n" " get { return $fileclass$.internal__$identifier$__Descriptor; }\r\n"
"}\r\n" "}\r\n"
"\r\n" "\r\n"
"protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors {\r\n" "protected override pb::FieldAccess.FieldAccessorTable<$classname$, $classname$.Builder> InternalFieldAccessors {\r\n"
" get { return $fileclass$.internal__$identifier$__FieldAccessorTable; }\r\n" " get { return $fileclass$.internal__$identifier$__FieldAccessorTable; }\r\n"
"}\r\n" "}\r\n"
"\r\n", "\r\n");
"fileclass", ClassName(descriptor_->file()),
"identifier", UniqueFileScopeIdentifier(descriptor_));
// Extensions don't need to go in an extra nested type // Extensions don't need to go in an extra nested type
for (int i = 0; i < descriptor_->extension_count(); i++) { for (int i = 0; i < descriptor_->extension_count(); i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment