diff options
Diffstat (limited to 'csharp/ProtocolBuffers/FieldAccess')
9 files changed, 96 insertions, 71 deletions
diff --git a/csharp/ProtocolBuffers/FieldAccess/Delegates.cs b/csharp/ProtocolBuffers/FieldAccess/Delegates.cs new file mode 100644 index 00000000..04b1d94c --- /dev/null +++ b/csharp/ProtocolBuffers/FieldAccess/Delegates.cs @@ -0,0 +1,11 @@ +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); +} diff --git a/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs b/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs index 24113b41..c7f5da6d 100644 --- a/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs +++ b/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs @@ -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."); diff --git a/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs index 3e47fdc6..eb57c8c9 100644 --- a/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs @@ -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 diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs index f6b273ee..3082071b 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs @@ -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)); diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs index d0c53dcc..f350752d 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs @@ -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); diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs index ad44991d..39184b1f 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs @@ -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) { diff --git a/csharp/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs index 7db6b182..eb28160a 100644 --- a/csharp/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs @@ -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); } diff --git a/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs index 7945f461..460d450d 100644 --- a/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs @@ -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)); } diff --git a/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs index efa77047..8d12b45c 100644 --- a/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs @@ -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(); } |