diff options
Diffstat (limited to 'csharp')
11 files changed, 197 insertions, 51 deletions
diff --git a/csharp/ProtocolBuffers/FieldAccess/Delegates.cs b/csharp/ProtocolBuffers/FieldAccess/Delegates.cs index 04b1d94c..e6fb4fe8 100644 --- a/csharp/ProtocolBuffers/FieldAccess/Delegates.cs +++ b/csharp/ProtocolBuffers/FieldAccess/Delegates.cs @@ -1,11 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Text; +// 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. namespace Google.ProtocolBuffers.FieldAccess { + // TODO(jonskeet): Convert these to Func/Action family delegate bool HasDelegate<T>(T message); delegate T ClearDelegate<T>(T builder); delegate int RepeatedCountDelegate<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); } diff --git a/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs index eb57c8c9..ec079f92 100644 --- a/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/IFieldAccessor.cs @@ -58,18 +58,18 @@ namespace Google.ProtocolBuffers.FieldAccess { /// <summary> /// Accessor for repeated fields /// </summary> - object GetRepeatedValue(IMessage message, int index); + object GetRepeatedValue(TMessage message, int index); /// <summary> /// Mutator for repeated fields /// </summary> - void SetRepeated(IBuilder builder, int index, object value); + void SetRepeated(TBuilder builder, int index, object value); /// <summary> /// Adds the specified value to the field in the given builder. /// </summary> - void AddRepeated(IBuilder builder, object value); + void AddRepeated(TBuilder builder, object value); /// <summary> /// Returns a read-only wrapper around the value of a repeated field. /// </summary> - object GetRepeatedWrapper(IBuilder builder); + object GetRepeatedWrapper(TBuilder builder); } } diff --git a/csharp/ProtocolBuffers/FieldAccess/ReflectionUtil.cs b/csharp/ProtocolBuffers/FieldAccess/ReflectionUtil.cs new file mode 100644 index 00000000..ca768a76 --- /dev/null +++ b/csharp/ProtocolBuffers/FieldAccess/ReflectionUtil.cs @@ -0,0 +1,118 @@ +// 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(); }; + } + } +} diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs index 3082071b..f00f7ee2 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs @@ -42,18 +42,18 @@ namespace Google.ProtocolBuffers.FieldAccess { 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 // its underlying value int rawValue = (int) base.GetRepeatedValue(message, index); 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); } - 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); } } diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs index f350752d..5c62782b 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs @@ -33,13 +33,14 @@ namespace Google.ProtocolBuffers.FieldAccess { /// in a message type "Foo", a field called "bar" might be of type "Baz". This /// method is Baz.CreateBuilder. /// </summary> - private readonly MethodInfo createBuilderMethod; + private readonly CreateBuilderDelegate createBuilderDelegate; internal RepeatedMessageAccessor(string name) : base(name) { - createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); + MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); if (createBuilderMethod == null) { throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name); } + createBuilderDelegate = ReflectionUtil.CreateStaticUpcastDelegate(createBuilderMethod); } /// <summary> @@ -58,15 +59,15 @@ namespace Google.ProtocolBuffers.FieldAccess { 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)); } 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)); } } diff --git a/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs index 39184b1f..0761635a 100644 --- a/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs @@ -25,13 +25,15 @@ namespace Google.ProtocolBuffers.FieldAccess { where TMessage : IMessage<TMessage, TBuilder> where TBuilder : IBuilder<TMessage, TBuilder> { - private readonly PropertyInfo messageProperty; - private readonly PropertyInfo builderProperty; - private readonly RepeatedCountDelegate<TMessage> countDelegate; + private readonly Type clrType; + private readonly GetValueDelegate<TMessage> getValueDelegate; 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 setElementMethod; + /// <summary> /// The CLR type of the field (int, the enum type, ByteString, the message etc). @@ -39,16 +41,17 @@ namespace Google.ProtocolBuffers.FieldAccess { /// value. /// </summary> protected Type ClrType { - get { return getElementMethod.ReturnType; } + get { return clrType; } } internal RepeatedPrimitiveAccessor(string name) { - messageProperty = typeof(TMessage).GetProperty(name + "List"); - builderProperty = typeof(TBuilder).GetProperty(name + "List"); + PropertyInfo messageProperty = typeof(TMessage).GetProperty(name + "List"); + PropertyInfo 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 }); + clrType = getElementMethod.ReturnType; + MethodInfo 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 @@ -62,6 +65,9 @@ namespace Google.ProtocolBuffers.FieldAccess { clearDelegate = (ClearDelegate<TBuilder>)Delegate.CreateDelegate(typeof(ClearDelegate<TBuilder>), clearMethod); countDelegate = (RepeatedCountDelegate<TMessage>)Delegate.CreateDelegate (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) { @@ -73,7 +79,7 @@ namespace Google.ProtocolBuffers.FieldAccess { } public virtual object GetValue(TMessage message) { - return messageProperty.GetValue(message, null); + return getValueDelegate(message); } public void SetValue(TBuilder builder, object value) { @@ -95,24 +101,24 @@ namespace Google.ProtocolBuffers.FieldAccess { 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 } ); } - 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} ); } - public virtual void AddRepeated(IBuilder builder, object value) { - addMethod.Invoke(builder, new object[] { value }); + public virtual void AddRepeated(TBuilder builder, object value) { + addValueDelegate(builder, value); } /// <summary> /// The builder class's accessor already builds a read-only wrapper for /// us, which is exactly what we want. /// </summary> - public object GetRepeatedWrapper(IBuilder builder) { - return builderProperty.GetValue(builder, null); + public object GetRepeatedWrapper(TBuilder builder) { + return getRepeatedWrapperDelegate(builder); } } }
\ No newline at end of file diff --git a/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs index 460d450d..fd6b5c9b 100644 --- a/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs @@ -29,15 +29,14 @@ namespace Google.ProtocolBuffers.FieldAccess { /// in a message type "Foo", a field called "bar" might be of type "Baz". This /// method is Baz.CreateBuilder. /// </summary> - private readonly MethodInfo createBuilderMethod; + private readonly CreateBuilderDelegate createBuilderDelegate; - - internal SingleMessageAccessor(string name) : base(name) { - - createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]);//BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); + internal SingleMessageAccessor(string name) : base(name) { + MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", new Type[0]); if (createBuilderMethod == null) { throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name); } + createBuilderDelegate = ReflectionUtil.CreateStaticUpcastDelegate(createBuilderMethod); } /// <summary> @@ -61,7 +60,7 @@ namespace Google.ProtocolBuffers.FieldAccess { } public override IBuilder CreateBuilder() { - return (IBuilder) createBuilderMethod.Invoke(null, null); + return createBuilderDelegate(); } } }
\ No newline at end of file diff --git a/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs b/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs index 8d12b45c..6c797370 100644 --- a/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs +++ b/csharp/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs @@ -24,8 +24,9 @@ namespace Google.ProtocolBuffers.FieldAccess { where TMessage : IMessage<TMessage, TBuilder> where TBuilder : IBuilder<TMessage, TBuilder> { - private readonly PropertyInfo messageProperty; - private readonly PropertyInfo builderProperty; + private readonly Type clrType; + private readonly GetValueDelegate<TMessage> getValueDelegate; + private readonly SingleValueDelegate<TBuilder> setValueDelegate; private readonly HasDelegate<TMessage> hasDelegate; private readonly ClearDelegate<TBuilder> clearDelegate; @@ -34,19 +35,22 @@ namespace Google.ProtocolBuffers.FieldAccess { /// As declared by the property. /// </summary> protected Type ClrType { - get { return messageProperty.PropertyType; } + get { return clrType; } } internal SinglePrimitiveAccessor(string name) { - messageProperty = typeof(TMessage).GetProperty(name); - builderProperty = typeof(TBuilder).GetProperty(name); + PropertyInfo messageProperty = typeof(TMessage).GetProperty(name); + PropertyInfo 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"); } + clrType = messageProperty.PropertyType; hasDelegate = (HasDelegate<TMessage>)Delegate.CreateDelegate(typeof(HasDelegate<TMessage>), hasProperty.GetGetMethod()); 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) { @@ -65,11 +69,11 @@ namespace Google.ProtocolBuffers.FieldAccess { } public virtual object GetValue(TMessage message) { - return messageProperty.GetValue(message, null); + return getValueDelegate(message); } public virtual void SetValue(TBuilder builder, object value) { - builderProperty.SetValue(builder, value, null); + setValueDelegate(builder, value); } #region Methods only related to repeated values @@ -77,19 +81,19 @@ namespace Google.ProtocolBuffers.FieldAccess { throw new InvalidOperationException(); } - public object GetRepeatedValue(IMessage message, int index) { + public object GetRepeatedValue(TMessage message, int index) { throw new InvalidOperationException(); } - public void SetRepeated(IBuilder builder, int index, object value) { + public void SetRepeated(TBuilder builder, int index, object value) { throw new InvalidOperationException(); } - public void AddRepeated(IBuilder builder, object value) { + public void AddRepeated(TBuilder builder, object value) { throw new InvalidOperationException(); } - public object GetRepeatedWrapper(IBuilder builder) { + public object GetRepeatedWrapper(TBuilder builder) { throw new InvalidOperationException(); } #endregion diff --git a/csharp/ProtocolBuffers/GeneratedBuilder.cs b/csharp/ProtocolBuffers/GeneratedBuilder.cs index 54d37392..a1c59e89 100644 --- a/csharp/ProtocolBuffers/GeneratedBuilder.cs +++ b/csharp/ProtocolBuffers/GeneratedBuilder.cs @@ -51,7 +51,7 @@ namespace Google.ProtocolBuffers { // For repeated fields, the underlying list object is still modifiable at this point. // Make sure not to expose the modifiable list to the caller. return field.IsRepeated - ? InternalFieldAccessors[field].GetRepeatedWrapper(this) + ? InternalFieldAccessors[field].GetRepeatedWrapper(ThisBuilder) : MessageBeingBuilt[field]; } set { @@ -92,7 +92,7 @@ namespace Google.ProtocolBuffers { public override object this[FieldDescriptor field, int 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) { @@ -144,7 +144,7 @@ namespace Google.ProtocolBuffers { } public override TBuilder AddRepeatedField(FieldDescriptor field, object value) { - InternalFieldAccessors[field].AddRepeated(this, value); + InternalFieldAccessors[field].AddRepeated(ThisBuilder, value); return ThisBuilder; } diff --git a/csharp/ProtocolBuffers/GeneratedMessage.cs b/csharp/ProtocolBuffers/GeneratedMessage.cs index 0fd54f6c..6198afbf 100644 --- a/csharp/ProtocolBuffers/GeneratedMessage.cs +++ b/csharp/ProtocolBuffers/GeneratedMessage.cs @@ -112,7 +112,7 @@ namespace Google.ProtocolBuffers { } 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] { diff --git a/csharp/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/ProtocolBuffers/ProtocolBuffers.csproj index c057b414..88a21226 100644 --- a/csharp/ProtocolBuffers/ProtocolBuffers.csproj +++ b/csharp/ProtocolBuffers/ProtocolBuffers.csproj @@ -72,6 +72,7 @@ <Compile Include="ExtensionInfo.cs" /> <Compile Include="ExtensionRegistry.cs" /> <Compile Include="FieldAccess\Delegates.cs" /> + <Compile Include="FieldAccess\ReflectionUtil.cs" /> <Compile Include="FieldAccess\SingleEnumAccessor.cs" /> <Compile Include="FieldAccess\SingleMessageAccessor.cs" /> <Compile Include="FieldAccess\SinglePrimitiveAccessor.cs" /> |