Commit 09809820 authored by Jon Skeet's avatar Jon Skeet

Evil reflection optimisation.

parent 38da52d3
using System; // Protocol Buffers - Google's data interchange format
using System.Collections.Generic; // Copyright 2008 Google Inc.
using System.Text; // http://code.google.com/p/protobuf/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Google.ProtocolBuffers.FieldAccess { namespace Google.ProtocolBuffers.FieldAccess {
// TODO(jonskeet): Convert these to Func/Action family
delegate bool HasDelegate<T>(T message); delegate bool HasDelegate<T>(T message);
delegate T ClearDelegate<T>(T builder); delegate T ClearDelegate<T>(T builder);
delegate int RepeatedCountDelegate<T>(T message); delegate int RepeatedCountDelegate<T>(T message);
delegate object GetValueDelegate<T>(T message); delegate object GetValueDelegate<T>(T message);
delegate void SingleValueDelegate<TSource>(TSource source, object value);
delegate IBuilder CreateBuilderDelegate();
delegate object GetIndexedValueDelegate<T>(T message, int index);
delegate object SetIndexedValueDelegate<T>(T message, int index, object value);
} }
...@@ -58,18 +58,18 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -58,18 +58,18 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// <summary> /// <summary>
/// Accessor for repeated fields /// Accessor for repeated fields
/// </summary> /// </summary>
object GetRepeatedValue(IMessage message, int index); object GetRepeatedValue(TMessage message, int index);
/// <summary> /// <summary>
/// Mutator for repeated fields /// Mutator for repeated fields
/// </summary> /// </summary>
void SetRepeated(IBuilder builder, int index, object value); void SetRepeated(TBuilder builder, int index, object value);
/// <summary> /// <summary>
/// Adds the specified value to the field in the given builder. /// Adds the specified value to the field in the given builder.
/// </summary> /// </summary>
void AddRepeated(IBuilder builder, object value); void AddRepeated(TBuilder builder, object value);
/// <summary> /// <summary>
/// Returns a read-only wrapper around the value of a repeated field. /// Returns a read-only wrapper around the value of a repeated field.
/// </summary> /// </summary>
object GetRepeatedWrapper(IBuilder builder); object GetRepeatedWrapper(TBuilder builder);
} }
} }
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.
// http://code.google.com/p/protobuf/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Reflection;
namespace Google.ProtocolBuffers.FieldAccess {
/// <summary>
/// The methods in this class are somewhat evil, and should not be tampered with lightly.
/// Basically they allow the creation of relatively weakly typed delegates from MethodInfos
/// which are more strongly typed. They do this by creating an appropriate strongly typed
/// delegate from the MethodInfo, and then calling that within an anonymous method.
/// Mind-bending stuff (at least to your humble narrator) but the resulting delegates are
/// very fast compared with calling Invoke later on.
/// </summary>
internal static class ReflectionUtil {
/// <summary>
/// Creates a delegate which will execute the given method and then return
/// the result as an object.
/// </summary>
public static GetValueDelegate<T> CreateUpcastDelegate<T>(MethodInfo method) {
// The tricky bit is invoking CreateCreateUpcastDelegateImpl with the right type parameters
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateUpcastDelegateImpl");
MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.ReturnType);
return (GetValueDelegate<T>) closedImpl.Invoke(null, new object[] { method });
}
delegate TResult Getter<TSource, TResult>(TSource source);
/// <summary>
/// Method used solely for implementing CreateUpcastDelegate. Public to avoid trust issues
/// in low-trust scenarios, e.g. Silverlight.
/// TODO(jonskeet): Check any of this actually works in Silverlight...
/// </summary>
public static GetValueDelegate<TSource> CreateUpcastDelegateImpl<TSource, TResult>(MethodInfo method) {
// Convert the reflection call into an open delegate, i.e. instead of calling x.Method()
// we'll call getter(x).
Getter<TSource, TResult> getter = (Getter<TSource, TResult>)Delegate.CreateDelegate(typeof(Getter<TSource, TResult>), method);
// Implicit upcast to object (within the delegate)
return delegate(TSource source) { return getter(source); };
}
/// <summary>
/// Creates a delegate which will execute the given method after casting the parameter
/// down from object to the required parameter type.
/// </summary>
public static SingleValueDelegate<T> CreateDowncastDelegate<T>(MethodInfo method) {
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateDowncastDelegateImpl");
MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.GetParameters()[0].ParameterType);
return (SingleValueDelegate<T>)closedImpl.Invoke(null, new object[] { method });
}
delegate void OpenSingleValueDelegate<TSource, TParam>(TSource source, TParam parameter);
public static SingleValueDelegate<TSource> CreateDowncastDelegateImpl<TSource, TParam>(MethodInfo method) {
// Convert the reflection call into an open delegate, i.e. instead of calling x.Method(y) we'll
// call Method(x, y)
OpenSingleValueDelegate<TSource, TParam> call = (OpenSingleValueDelegate<TSource, TParam>)
Delegate.CreateDelegate(typeof(OpenSingleValueDelegate<TSource, TParam>), method);
return delegate(TSource source, object parameter) { call(source, (TParam)parameter); };
}
/// <summary>
/// Creates a delegate which will execute the given method after casting the parameter
/// down from object to the required parameter type.
/// </summary>
public static SingleValueDelegate<T> CreateDowncastDelegateIgnoringReturn<T>(MethodInfo method) {
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateDowncastDelegateIgnoringReturnImpl");
MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.GetParameters()[0].ParameterType, method.ReturnType);
return (SingleValueDelegate<T>)closedImpl.Invoke(null, new object[] { method });
}
delegate TReturn OpenSingleValueDelegate<TSource, TParam, TReturn>(TSource source, TParam parameter);
public static SingleValueDelegate<TSource> CreateDowncastDelegateIgnoringReturnImpl<TSource, TParam, TReturn>(MethodInfo method) {
// Convert the reflection call into an open delegate, i.e. instead of calling x.Method(y) we'll
// call Method(x, y)
OpenSingleValueDelegate<TSource, TParam, TReturn> call = (OpenSingleValueDelegate<TSource, TParam, TReturn>)
Delegate.CreateDelegate(typeof(OpenSingleValueDelegate<TSource, TParam, TReturn>), method);
return delegate(TSource source, object parameter) { call(source, (TParam)parameter); };
}
delegate T OpenCreateBuilderDelegate<T>();
/// <summary>
/// Creates a delegate which will execute the given static method and cast the result up to IBuilder.
/// </summary>
public static CreateBuilderDelegate CreateStaticUpcastDelegate(MethodInfo method) {
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateStaticUpcastDelegateImpl");
MethodInfo closedImpl = openImpl.MakeGenericMethod(method.ReturnType);
return (CreateBuilderDelegate) closedImpl.Invoke(null, new object[] { method });
}
public static CreateBuilderDelegate CreateStaticUpcastDelegateImpl<T>(MethodInfo method) {
OpenCreateBuilderDelegate<T> call = (OpenCreateBuilderDelegate<T>)Delegate.CreateDelegate(typeof(OpenCreateBuilderDelegate<T>), method);
return delegate { return (IBuilder)call(); };
}
}
}
...@@ -42,18 +42,18 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -42,18 +42,18 @@ namespace Google.ProtocolBuffers.FieldAccess {
return Lists.AsReadOnly(ret); return Lists.AsReadOnly(ret);
} }
public override object GetRepeatedValue(IMessage message, int index) { public override object GetRepeatedValue(TMessage message, int index) {
// 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.GetRepeatedValue(message, index); int rawValue = (int) base.GetRepeatedValue(message, index);
return enumDescriptor.FindValueByNumber(rawValue); return enumDescriptor.FindValueByNumber(rawValue);
} }
public override void AddRepeated(IBuilder builder, object value) { public override void AddRepeated(TBuilder builder, object value) {
base.AddRepeated(builder, ((EnumValueDescriptor) value).Number); base.AddRepeated(builder, ((EnumValueDescriptor) value).Number);
} }
public override void SetRepeated(IBuilder builder, int index, object value) { public override void SetRepeated(TBuilder builder, int index, object value) {
base.SetRepeated(builder, index, ((EnumValueDescriptor) value).Number); base.SetRepeated(builder, index, ((EnumValueDescriptor) value).Number);
} }
} }
......
...@@ -33,13 +33,14 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -33,13 +33,14 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// in a message type "Foo", a field called "bar" might be of type "Baz". This /// in a message type "Foo", a field called "bar" might be of type "Baz". This
/// method is Baz.CreateBuilder. /// method is Baz.CreateBuilder.
/// </summary> /// </summary>
private readonly MethodInfo createBuilderMethod; private readonly CreateBuilderDelegate createBuilderDelegate;
internal RepeatedMessageAccessor(string name) : base(name) { internal RepeatedMessageAccessor(string name) : base(name) {
createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); MethodInfo 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);
} }
createBuilderDelegate = ReflectionUtil.CreateStaticUpcastDelegate(createBuilderMethod);
} }
/// <summary> /// <summary>
...@@ -58,15 +59,15 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -58,15 +59,15 @@ namespace Google.ProtocolBuffers.FieldAccess {
return CreateBuilder().WeakMergeFrom(message).WeakBuild(); return CreateBuilder().WeakMergeFrom(message).WeakBuild();
} }
public override void SetRepeated(IBuilder builder, int index, object value) { public override void SetRepeated(TBuilder builder, int index, object value) {
base.SetRepeated(builder, index, CoerceType(value)); base.SetRepeated(builder, index, CoerceType(value));
} }
public override IBuilder CreateBuilder() { public override IBuilder CreateBuilder() {
return (IBuilder) createBuilderMethod.Invoke(null, null); return createBuilderDelegate();
} }
public override void AddRepeated(IBuilder builder, object value) { public override void AddRepeated(TBuilder builder, object value) {
base.AddRepeated(builder, CoerceType(value)); base.AddRepeated(builder, CoerceType(value));
} }
} }
......
...@@ -25,30 +25,33 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -25,30 +25,33 @@ namespace Google.ProtocolBuffers.FieldAccess {
where TMessage : IMessage<TMessage, TBuilder> where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> { where TBuilder : IBuilder<TMessage, TBuilder> {
private readonly PropertyInfo messageProperty; private readonly Type clrType;
private readonly PropertyInfo builderProperty; private readonly GetValueDelegate<TMessage> getValueDelegate;
private readonly RepeatedCountDelegate<TMessage> countDelegate;
private readonly ClearDelegate<TBuilder> clearDelegate; private readonly ClearDelegate<TBuilder> clearDelegate;
private readonly MethodInfo addMethod; private readonly SingleValueDelegate<TBuilder> addValueDelegate;
private readonly GetValueDelegate<TBuilder> getRepeatedWrapperDelegate;
private readonly RepeatedCountDelegate<TMessage> countDelegate;
private readonly MethodInfo getElementMethod; private readonly MethodInfo getElementMethod;
private readonly MethodInfo setElementMethod; private readonly MethodInfo setElementMethod;
/// <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).
/// This is taken from the return type of the method used to retrieve a single /// This is taken from the return type of the method used to retrieve a single
/// value. /// value.
/// </summary> /// </summary>
protected Type ClrType { protected Type ClrType {
get { return getElementMethod.ReturnType; } get { return clrType; }
} }
internal RepeatedPrimitiveAccessor(string name) { internal RepeatedPrimitiveAccessor(string name) {
messageProperty = typeof(TMessage).GetProperty(name + "List"); PropertyInfo messageProperty = typeof(TMessage).GetProperty(name + "List");
builderProperty = typeof(TBuilder).GetProperty(name + "List"); PropertyInfo builderProperty = typeof(TBuilder).GetProperty(name + "List");
PropertyInfo countProperty = typeof(TMessage).GetProperty(name + "Count"); PropertyInfo countProperty = typeof(TMessage).GetProperty(name + "Count");
MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name); MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
getElementMethod = typeof(TMessage).GetMethod("Get" + name, new Type[] { typeof(int) }); getElementMethod = typeof(TMessage).GetMethod("Get" + name, new Type[] { typeof(int) });
addMethod = typeof(TBuilder).GetMethod("Add" + name, new Type[] { ClrType }); clrType = getElementMethod.ReturnType;
MethodInfo addMethod = typeof(TBuilder).GetMethod("Add" + name, new Type[] { ClrType });
setElementMethod = typeof(TBuilder).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
...@@ -62,6 +65,9 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -62,6 +65,9 @@ namespace Google.ProtocolBuffers.FieldAccess {
clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod); clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod);
countDelegate = (RepeatedCountDelegate<TMessage>)Delegate.CreateDelegate countDelegate = (RepeatedCountDelegate<TMessage>)Delegate.CreateDelegate
(typeof(RepeatedCountDelegate<TMessage>), countProperty.GetGetMethod()); (typeof(RepeatedCountDelegate<TMessage>), countProperty.GetGetMethod());
getValueDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(messageProperty.GetGetMethod());
addValueDelegate = ReflectionUtil.CreateDowncastDelegateIgnoringReturn<TBuilder>(addMethod);
getRepeatedWrapperDelegate = ReflectionUtil.CreateUpcastDelegate<TBuilder>(builderProperty.GetGetMethod());
} }
public bool Has(TMessage message) { public bool Has(TMessage message) {
...@@ -73,7 +79,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -73,7 +79,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
} }
public virtual object GetValue(TMessage message) { public virtual object GetValue(TMessage message) {
return messageProperty.GetValue(message, null); return getValueDelegate(message);
} }
public void SetValue(TBuilder builder, object value) { public void SetValue(TBuilder builder, object value) {
...@@ -95,24 +101,24 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -95,24 +101,24 @@ namespace Google.ProtocolBuffers.FieldAccess {
return countDelegate(message); return countDelegate(message);
} }
public virtual object GetRepeatedValue(IMessage message, int index) { public virtual object GetRepeatedValue(TMessage message, int index) {
return getElementMethod.Invoke(message, new object[] {index } ); return getElementMethod.Invoke(message, new object[] {index } );
} }
public virtual void SetRepeated(IBuilder builder, int index, object value) { public virtual void SetRepeated(TBuilder builder, int index, object value) {
setElementMethod.Invoke(builder, new object[] {index, value} ); setElementMethod.Invoke(builder, new object[] {index, value} );
} }
public virtual void AddRepeated(IBuilder builder, object value) { public virtual void AddRepeated(TBuilder builder, object value) {
addMethod.Invoke(builder, new object[] { value }); addValueDelegate(builder, value);
} }
/// <summary> /// <summary>
/// The builder class's accessor already builds a read-only wrapper for /// The builder class's accessor already builds a read-only wrapper for
/// us, which is exactly what we want. /// us, which is exactly what we want.
/// </summary> /// </summary>
public object GetRepeatedWrapper(IBuilder builder) { public object GetRepeatedWrapper(TBuilder builder) {
return builderProperty.GetValue(builder, null); return getRepeatedWrapperDelegate(builder);
} }
} }
} }
\ No newline at end of file
...@@ -29,15 +29,14 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -29,15 +29,14 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// in a message type "Foo", a field called "bar" might be of type "Baz". This /// in a message type "Foo", a field called "bar" might be of type "Baz". This
/// method is Baz.CreateBuilder. /// method is Baz.CreateBuilder.
/// </summary> /// </summary>
private readonly MethodInfo createBuilderMethod; private readonly CreateBuilderDelegate createBuilderDelegate;
internal SingleMessageAccessor(string name) : base(name) { internal SingleMessageAccessor(string name) : base(name) {
MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]);
createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]);//BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
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);
} }
createBuilderDelegate = ReflectionUtil.CreateStaticUpcastDelegate(createBuilderMethod);
} }
/// <summary> /// <summary>
...@@ -61,7 +60,7 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -61,7 +60,7 @@ namespace Google.ProtocolBuffers.FieldAccess {
} }
public override IBuilder CreateBuilder() { public override IBuilder CreateBuilder() {
return (IBuilder) createBuilderMethod.Invoke(null, null); return createBuilderDelegate();
} }
} }
} }
\ No newline at end of file
...@@ -24,8 +24,9 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -24,8 +24,9 @@ namespace Google.ProtocolBuffers.FieldAccess {
where TMessage : IMessage<TMessage, TBuilder> where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> { where TBuilder : IBuilder<TMessage, TBuilder> {
private readonly PropertyInfo messageProperty; private readonly Type clrType;
private readonly PropertyInfo builderProperty; private readonly GetValueDelegate<TMessage> getValueDelegate;
private readonly SingleValueDelegate<TBuilder> setValueDelegate;
private readonly HasDelegate<TMessage> hasDelegate; private readonly HasDelegate<TMessage> hasDelegate;
private readonly ClearDelegate<TBuilder> clearDelegate; private readonly ClearDelegate<TBuilder> clearDelegate;
...@@ -34,19 +35,22 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -34,19 +35,22 @@ namespace Google.ProtocolBuffers.FieldAccess {
/// As declared by the property. /// As declared by the property.
/// </summary> /// </summary>
protected Type ClrType { protected Type ClrType {
get { return messageProperty.PropertyType; } get { return clrType; }
} }
internal SinglePrimitiveAccessor(string name) { internal SinglePrimitiveAccessor(string name) {
messageProperty = typeof(TMessage).GetProperty(name); PropertyInfo messageProperty = typeof(TMessage).GetProperty(name);
builderProperty = typeof(TBuilder).GetProperty(name); PropertyInfo builderProperty = typeof(TBuilder).GetProperty(name);
PropertyInfo hasProperty = typeof(TMessage).GetProperty("Has" + name); PropertyInfo hasProperty = typeof(TMessage).GetProperty("Has" + name);
MethodInfo clearMethod = typeof(TBuilder).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");
} }
clrType = messageProperty.PropertyType;
hasDelegate = (HasDelegate<TMessage>)Delegate.CreateDelegate(typeof(HasDelegate<TMessage>), hasProperty.GetGetMethod()); hasDelegate = (HasDelegate<TMessage>)Delegate.CreateDelegate(typeof(HasDelegate<TMessage>), hasProperty.GetGetMethod());
clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod); clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod);
getValueDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(messageProperty.GetGetMethod());
setValueDelegate = ReflectionUtil.CreateDowncastDelegate<TBuilder>(builderProperty.GetSetMethod());
} }
public bool Has(TMessage message) { public bool Has(TMessage message) {
...@@ -65,11 +69,11 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -65,11 +69,11 @@ namespace Google.ProtocolBuffers.FieldAccess {
} }
public virtual object GetValue(TMessage message) { public virtual object GetValue(TMessage message) {
return messageProperty.GetValue(message, null); return getValueDelegate(message);
} }
public virtual void SetValue(TBuilder builder, object value) { public virtual void SetValue(TBuilder builder, object value) {
builderProperty.SetValue(builder, value, null); setValueDelegate(builder, value);
} }
#region Methods only related to repeated values #region Methods only related to repeated values
...@@ -77,19 +81,19 @@ namespace Google.ProtocolBuffers.FieldAccess { ...@@ -77,19 +81,19 @@ namespace Google.ProtocolBuffers.FieldAccess {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public object GetRepeatedValue(IMessage message, int index) { public object GetRepeatedValue(TMessage message, int index) {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public void SetRepeated(IBuilder builder, int index, object value) { public void SetRepeated(TBuilder builder, int index, object value) {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public void AddRepeated(IBuilder builder, object value) { public void AddRepeated(TBuilder builder, object value) {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public object GetRepeatedWrapper(IBuilder builder) { public object GetRepeatedWrapper(TBuilder builder) {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
#endregion #endregion
......
...@@ -51,7 +51,7 @@ namespace Google.ProtocolBuffers { ...@@ -51,7 +51,7 @@ namespace Google.ProtocolBuffers {
// For repeated fields, the underlying list object is still modifiable at this point. // For repeated fields, the underlying list object is still modifiable at this point.
// Make sure not to expose the modifiable list to the caller. // Make sure not to expose the modifiable list to the caller.
return field.IsRepeated return field.IsRepeated
? InternalFieldAccessors[field].GetRepeatedWrapper(this) ? InternalFieldAccessors[field].GetRepeatedWrapper(ThisBuilder)
: MessageBeingBuilt[field]; : MessageBeingBuilt[field];
} }
set { set {
...@@ -92,7 +92,7 @@ namespace Google.ProtocolBuffers { ...@@ -92,7 +92,7 @@ namespace Google.ProtocolBuffers {
public override object this[FieldDescriptor field, int index] { public override object this[FieldDescriptor field, int index] {
get { return MessageBeingBuilt[field, index]; } get { return MessageBeingBuilt[field, index]; }
set { InternalFieldAccessors[field].SetRepeated(this, index, value); } set { InternalFieldAccessors[field].SetRepeated(ThisBuilder, index, value); }
} }
public override bool HasField(FieldDescriptor field) { public override bool HasField(FieldDescriptor field) {
...@@ -144,7 +144,7 @@ namespace Google.ProtocolBuffers { ...@@ -144,7 +144,7 @@ namespace Google.ProtocolBuffers {
} }
public override TBuilder AddRepeatedField(FieldDescriptor field, object value) { public override TBuilder AddRepeatedField(FieldDescriptor field, object value) {
InternalFieldAccessors[field].AddRepeated(this, value); InternalFieldAccessors[field].AddRepeated(ThisBuilder, value);
return ThisBuilder; return ThisBuilder;
} }
......
...@@ -112,7 +112,7 @@ namespace Google.ProtocolBuffers { ...@@ -112,7 +112,7 @@ namespace Google.ProtocolBuffers {
} }
public override object this[FieldDescriptor field, int index] { public override object this[FieldDescriptor field, int index] {
get { return InternalFieldAccessors[field].GetRepeatedValue(this, index); } get { return InternalFieldAccessors[field].GetRepeatedValue(ThisMessage, index); }
} }
public override object this[FieldDescriptor field] { public override object this[FieldDescriptor field] {
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
<Compile Include="ExtensionInfo.cs" /> <Compile Include="ExtensionInfo.cs" />
<Compile Include="ExtensionRegistry.cs" /> <Compile Include="ExtensionRegistry.cs" />
<Compile Include="FieldAccess\Delegates.cs" /> <Compile Include="FieldAccess\Delegates.cs" />
<Compile Include="FieldAccess\ReflectionUtil.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" />
......
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