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