aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/ProtocolBuffers/FieldAccess
diff options
context:
space:
mode:
authorJie Luo <anandolee@gmail.com>2015-05-14 14:54:36 -0700
committerJie Luo <anandolee@gmail.com>2015-05-14 14:54:36 -0700
commitaa8c951ef58dbc6a5c1ec8118980938f20916ce8 (patch)
tree07075ec40b4ebb013bd2f12c82d2f7f0c47b7b1b /csharp/src/ProtocolBuffers/FieldAccess
parentb481a4f920d2f5872bc1e9bfd6b0656f6ad0b713 (diff)
parent2d9b1c592ff7319ee9d6520c9df4838087522e05 (diff)
downloadprotobuf-aa8c951ef58dbc6a5c1ec8118980938f20916ce8.tar.gz
protobuf-aa8c951ef58dbc6a5c1ec8118980938f20916ce8.tar.bz2
protobuf-aa8c951ef58dbc6a5c1ec8118980938f20916ce8.zip
Merge pull request #384 from google/csharp
Merge protobuf C# into master (only C# proto2 is supported)
Diffstat (limited to 'csharp/src/ProtocolBuffers/FieldAccess')
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs127
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/IFieldAccessor.cs95
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs189
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs83
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs97
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs158
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs74
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs89
-rw-r--r--csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs146
9 files changed, 1058 insertions, 0 deletions
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs b/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
new file mode 100644
index 00000000..6e20b14e
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
@@ -0,0 +1,127 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Provides access to fields in generated messages via reflection.
+ /// This type is public to allow it to be used by generated messages, which
+ /// create appropriate instances in the .proto file description class.
+ /// TODO(jonskeet): See if we can hide it somewhere...
+ /// </summary>
+ public sealed class FieldAccessorTable<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage, TBuilder>
+ where TBuilder : IBuilder<TMessage, TBuilder>
+ {
+ private readonly IFieldAccessor<TMessage, TBuilder>[] accessors;
+
+ private readonly MessageDescriptor descriptor;
+
+ public MessageDescriptor Descriptor
+ {
+ get { return descriptor; }
+ }
+
+ /// <summary>
+ /// Constructs a FieldAccessorTable for a particular message class.
+ /// Only one FieldAccessorTable should be constructed per class.
+ /// The property names should all actually correspond with the field descriptor's
+ /// CSharpOptions.PropertyName property, but bootstrapping issues currently
+ /// prevent us from using that. This may be addressed at a future time, in which case
+ /// we can keep this constructor for backwards compatibility, just ignoring the parameter.
+ /// TODO(jonskeet): Make it so.
+ /// </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>
+ public FieldAccessorTable(MessageDescriptor descriptor, String[] propertyNames)
+ {
+ this.descriptor = descriptor;
+ accessors = new IFieldAccessor<TMessage, TBuilder>[descriptor.Fields.Count];
+ bool supportFieldPresence = descriptor.File.Syntax == FileDescriptor.ProtoSyntax.Proto2;
+ for (int i = 0; i < accessors.Length; i++)
+ {
+ accessors[i] = CreateAccessor(descriptor.Fields[i], propertyNames[i], supportFieldPresence);
+ }
+ }
+
+ /// <summary>
+ /// Creates an accessor for a single field
+ /// </summary>
+ private static IFieldAccessor<TMessage, TBuilder> CreateAccessor(FieldDescriptor field, string name, bool supportFieldPresence)
+ {
+ if (field.IsRepeated)
+ {
+ switch (field.MappedType)
+ {
+ 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<TMessage, TBuilder>(name);
+ case MappedType.Enum:
+ return new SingleEnumAccessor<TMessage, TBuilder>(field, name, supportFieldPresence);
+ default:
+ return new SinglePrimitiveAccessor<TMessage, TBuilder>(field, name, supportFieldPresence);
+ }
+ }
+ }
+
+ internal IFieldAccessor<TMessage, TBuilder> this[FieldDescriptor field]
+ {
+ get
+ {
+ if (field.ContainingType != descriptor)
+ {
+ throw new ArgumentException("FieldDescriptor does not match message type.");
+ }
+ else if (field.IsExtension)
+ {
+ // If this type had extensions, it would subclass ExtendableMessage,
+ // which overrides the reflection interface to handle extensions.
+ throw new ArgumentException("This type does not have extensions.");
+ }
+ return accessors[field.Index];
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/IFieldAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/IFieldAccessor.cs
new file mode 100644
index 00000000..39d3b85b
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/IFieldAccessor.cs
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Allows fields to be reflectively accessed in a smart manner.
+ /// 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<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage, TBuilder>
+ where TBuilder : IBuilder<TMessage, TBuilder>
+ {
+ /// <summary>
+ /// Indicates whether the specified message contains the field.
+ /// </summary>
+ bool Has(TMessage message);
+
+ /// <summary>
+ /// Gets the count of the repeated field in the specified message.
+ /// </summary>
+ int GetRepeatedCount(TMessage message);
+
+ /// <summary>
+ /// Clears the field in the specified builder.
+ /// </summary>
+ /// <param name="builder"></param>
+ void Clear(TBuilder builder);
+
+ /// <summary>
+ /// Creates a builder for the type of this field (which must be a message field).
+ /// </summary>
+ IBuilder CreateBuilder();
+
+ /// <summary>
+ /// Accessor for single fields
+ /// </summary>
+ object GetValue(TMessage message);
+
+ /// <summary>
+ /// Mutator for single fields
+ /// </summary>
+ void SetValue(TBuilder builder, object value);
+
+ /// <summary>
+ /// Accessor for repeated fields
+ /// </summary>
+ object GetRepeatedValue(TMessage message, int index);
+
+ /// <summary>
+ /// Mutator for repeated fields
+ /// </summary>
+ void SetRepeated(TBuilder builder, int index, object value);
+
+ /// <summary>
+ /// Adds the specified value to the field in the given builder.
+ /// </summary>
+ void AddRepeated(TBuilder builder, object value);
+
+ /// <summary>
+ /// Returns a read-only wrapper around the value of a repeated field.
+ /// </summary>
+ object GetRepeatedWrapper(TBuilder builder);
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs b/csharp/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs
new file mode 100644
index 00000000..798f0dd7
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs
@@ -0,0 +1,189 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+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>
+ /// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
+ /// </summary>
+ internal static readonly Type[] EmptyTypes = new Type[0];
+
+ /// <summary>
+ /// Creates a delegate which will execute the given method and then return
+ /// the result as an object.
+ /// </summary>
+ public static Func<T, object> 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 (Func<T, object>) closedImpl.Invoke(null, new object[] {method});
+ }
+
+ /// <summary>
+ /// Method used solely for implementing CreateUpcastDelegate. Public to avoid trust issues
+ /// in low-trust scenarios.
+ /// </summary>
+ public static Func<TSource, object> 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).
+ Func<TSource, TResult> getter = ReflectionUtil.CreateDelegateFunc<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 Action<T, object> CreateDowncastDelegate<T>(MethodInfo method)
+ {
+ MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateDowncastDelegateImpl");
+ MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.GetParameters()[0].ParameterType);
+ return (Action<T, object>) closedImpl.Invoke(null, new object[] {method});
+ }
+
+ public static Action<TSource, object> 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)
+ Action<TSource, TParam> call = ReflectionUtil.CreateDelegateAction<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 Action<T, object> CreateDowncastDelegateIgnoringReturn<T>(MethodInfo method)
+ {
+ MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateDowncastDelegateIgnoringReturnImpl");
+ MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.GetParameters()[0].ParameterType,
+ method.ReturnType);
+ return (Action<T, object>) closedImpl.Invoke(null, new object[] {method});
+ }
+
+ public static Action<TSource, object> 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)
+ Func<TSource, TParam, TReturn> call = ReflectionUtil.CreateDelegateFunc<TSource, TParam, TReturn>(method);
+
+ return delegate(TSource source, object parameter) { call(source, (TParam) parameter); };
+ }
+
+ /// <summary>
+ /// Creates a delegate which will execute the given static method and cast the result up to IBuilder.
+ /// </summary>
+ public static Func<IBuilder> CreateStaticUpcastDelegate(MethodInfo method)
+ {
+ MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateStaticUpcastDelegateImpl");
+ MethodInfo closedImpl = openImpl.MakeGenericMethod(method.ReturnType);
+ return (Func<IBuilder>) closedImpl.Invoke(null, new object[] {method});
+ }
+
+ public static Func<IBuilder> CreateStaticUpcastDelegateImpl<T>(MethodInfo method)
+ {
+ Func<T> call = ReflectionUtil.CreateDelegateFunc<T>(method);
+ return delegate { return (IBuilder) call(); };
+ }
+
+
+ internal static Func<TResult> CreateDelegateFunc<TResult>(MethodInfo method)
+ {
+#if !CF20
+ object tdelegate = Delegate.CreateDelegate(typeof(Func<TResult>), null, method);
+ return (Func<TResult>)tdelegate;
+#else
+ return delegate() { return (TResult)method.Invoke(null, null); };
+#endif
+ }
+
+ internal static Func<T, TResult> CreateDelegateFunc<T, TResult>(MethodInfo method)
+ {
+#if !CF20
+ object tdelegate = Delegate.CreateDelegate(typeof(Func<T, TResult>), null, method);
+ return (Func<T, TResult>)tdelegate;
+#else
+ if (method.IsStatic)
+ {
+ return delegate(T arg1) { return (TResult) method.Invoke(null, new object[] {arg1}); };
+ }
+ return delegate(T arg1) { return (TResult)method.Invoke(arg1, null); };
+#endif
+ }
+
+ internal static Func<T1, T2, TResult> CreateDelegateFunc<T1, T2, TResult>(MethodInfo method)
+ {
+#if !CF20
+ object tdelegate = Delegate.CreateDelegate(typeof(Func<T1, T2, TResult>), null, method);
+ return (Func<T1, T2, TResult>)tdelegate;
+#else
+ if (method.IsStatic)
+ {
+ return delegate(T1 arg1, T2 arg2) { return (TResult) method.Invoke(null, new object[] {arg1, arg2}); };
+ }
+ return delegate(T1 arg1, T2 arg2) { return (TResult)method.Invoke(arg1, new object[] { arg2 }); };
+#endif
+ }
+
+ internal static Action<T1, T2> CreateDelegateAction<T1, T2>(MethodInfo method)
+ {
+#if !CF20
+ object tdelegate = Delegate.CreateDelegate(typeof(Action<T1, T2>), null, method);
+ return (Action<T1, T2>)tdelegate;
+#else
+ if (method.IsStatic)
+ {
+ return delegate(T1 arg1, T2 arg2) { method.Invoke(null, new object[] {arg1, arg2}); };
+ }
+ return delegate(T1 arg1, T2 arg2) { method.Invoke(arg1, new object[] { arg2 }); };
+#endif
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs
new file mode 100644
index 00000000..152c2e0a
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/RepeatedEnumAccessor.cs
@@ -0,0 +1,83 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System.Collections;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Collections;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Accessor for a repeated enum field.
+ /// </summary>
+ 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) : base(name)
+ {
+ enumDescriptor = field.EnumType;
+ }
+
+ 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));
+ }
+ return Lists.AsReadOnly(ret);
+ }
+
+ 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(TBuilder builder, object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "value");
+ base.AddRepeated(builder, ((EnumValueDescriptor) value).Number);
+ }
+
+ public override void SetRepeated(TBuilder builder, int index, object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "value");
+ base.SetRepeated(builder, index, ((EnumValueDescriptor) value).Number);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs
new file mode 100644
index 00000000..fd18b904
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/RepeatedMessageAccessor.cs
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Reflection;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Accessor for a repeated message field.
+ ///
+ /// TODO(jonskeet): Try to extract the commonality between this and SingleMessageAccessor.
+ /// We almost want multiple inheritance...
+ /// </summary>
+ 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,
+ /// in a message type "Foo", a field called "bar" might be of type "Baz". This
+ /// method is Baz.CreateBuilder.
+ /// </summary>
+ private readonly Func<IBuilder> createBuilderDelegate;
+
+ internal RepeatedMessageAccessor(string name) : base(name)
+ {
+ MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", EmptyTypes);
+ if (createBuilderMethod == null)
+ {
+ throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name);
+ }
+ createBuilderDelegate = ReflectionUtil.CreateStaticUpcastDelegate(createBuilderMethod);
+ }
+
+ /// <summary>
+ /// Creates a message of the appropriate CLR type from the given value,
+ /// which may already be of the right type or may be a dynamic message.
+ /// </summary>
+ private object CoerceType(object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "value");
+ // If it's already of the right type, we're done
+ if (ClrType.IsInstanceOfType(value))
+ {
+ return value;
+ }
+
+ // No... so let's create a builder of the right type, and merge the value in.
+ IMessageLite message = (IMessageLite) value;
+ return CreateBuilder().WeakMergeFrom(message).WeakBuild();
+ }
+
+ public override void SetRepeated(TBuilder builder, int index, object value)
+ {
+ base.SetRepeated(builder, index, CoerceType(value));
+ }
+
+ public override IBuilder CreateBuilder()
+ {
+ return createBuilderDelegate();
+ }
+
+ public override void AddRepeated(TBuilder builder, object value)
+ {
+ base.AddRepeated(builder, CoerceType(value));
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs
new file mode 100644
index 00000000..d3b926bc
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs
@@ -0,0 +1,158 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Collections;
+using System.Reflection;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Accessor for a repeated field of type int, ByteString etc.
+ /// </summary>
+ internal class RepeatedPrimitiveAccessor<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage, TBuilder>
+ where TBuilder : IBuilder<TMessage, TBuilder>
+ {
+ private readonly Type clrType;
+ private readonly Func<TMessage, object> getValueDelegate;
+ private readonly Func<TBuilder, IBuilder> clearDelegate;
+ private readonly Action<TBuilder, object> addValueDelegate;
+ private readonly Func<TBuilder, object> getRepeatedWrapperDelegate;
+ private readonly Func<TMessage, int> countDelegate;
+ private readonly MethodInfo getElementMethod;
+ private readonly MethodInfo setElementMethod;
+
+ // Replacement for Type.EmptyTypes which apparently isn't available on the compact framework
+ internal static readonly Type[] EmptyTypes = new Type[0];
+
+ /// <summary>
+ /// 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
+ /// value.
+ /// </summary>
+ protected Type ClrType
+ {
+ get { return clrType; }
+ }
+
+ internal RepeatedPrimitiveAccessor(string name)
+ {
+ 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, EmptyTypes);
+ getElementMethod = typeof(TMessage).GetMethod("Get" + name, new Type[] {typeof(int)});
+ 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
+ || countProperty == null
+ || clearMethod == null
+ || addMethod == null
+ || getElementMethod == null
+ || setElementMethod == null)
+ {
+ throw new ArgumentException("Not all required properties/methods available");
+ }
+ clearDelegate = ReflectionUtil.CreateDelegateFunc<TBuilder, IBuilder>(clearMethod);
+ countDelegate = ReflectionUtil.CreateDelegateFunc<TMessage, int>(countProperty.GetGetMethod());
+ getValueDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(messageProperty.GetGetMethod());
+ addValueDelegate = ReflectionUtil.CreateDowncastDelegateIgnoringReturn<TBuilder>(addMethod);
+ getRepeatedWrapperDelegate = ReflectionUtil.CreateUpcastDelegate<TBuilder>(builderProperty.GetGetMethod());
+ }
+
+ public bool Has(TMessage message)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public virtual IBuilder CreateBuilder()
+ {
+ throw new InvalidOperationException();
+ }
+
+ public virtual object GetValue(TMessage message)
+ {
+ return getValueDelegate(message);
+ }
+
+ 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
+ // have the modifications be reflected in the message.
+ Clear(builder);
+ foreach (object element in (IEnumerable) value)
+ {
+ AddRepeated(builder, element);
+ }
+ }
+
+ public void Clear(TBuilder builder)
+ {
+ clearDelegate(builder);
+ }
+
+ public int GetRepeatedCount(TMessage message)
+ {
+ return countDelegate(message);
+ }
+
+ public virtual object GetRepeatedValue(TMessage message, int index)
+ {
+ return getElementMethod.Invoke(message, new object[] {index});
+ }
+
+ public virtual void SetRepeated(TBuilder builder, int index, object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "value");
+ setElementMethod.Invoke(builder, new object[] {index, value});
+ }
+
+ public virtual void AddRepeated(TBuilder builder, object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "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(TBuilder builder)
+ {
+ return getRepeatedWrapperDelegate(builder);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs
new file mode 100644
index 00000000..e63f717c
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs
@@ -0,0 +1,74 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Accessor for fields representing a non-repeated enum value.
+ /// </summary>
+ 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, bool supportFieldPresence) : base(field, name, supportFieldPresence)
+ {
+ enumDescriptor = field.EnumType;
+ }
+
+ /// <summary>
+ /// Returns an EnumValueDescriptor representing the value in the builder.
+ /// 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(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);
+ return enumDescriptor.FindValueByNumber(rawValue);
+ }
+
+ /// <summary>
+ /// Sets the value as an enum (via an int) in the builder,
+ /// from an EnumValueDescriptor parameter.
+ /// </summary>
+ public override void SetValue(TBuilder builder, object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "value");
+ EnumValueDescriptor valueDescriptor = (EnumValueDescriptor) value;
+ base.SetValue(builder, valueDescriptor.Number);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs
new file mode 100644
index 00000000..0ec2b0b7
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs
@@ -0,0 +1,89 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Reflection;
+
+namespace Google.ProtocolBuffers.FieldAccess
+{
+ /// <summary>
+ /// Accessor for fields representing a non-repeated message value.
+ /// </summary>
+ 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,
+ /// in a message type "Foo", a field called "bar" might be of type "Baz". This
+ /// method is Baz.CreateBuilder.
+ /// </summary>
+ private readonly Func<IBuilder> createBuilderDelegate;
+
+ internal SingleMessageAccessor(string name) : base(null, name, true)
+ {
+ MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", ReflectionUtil.EmptyTypes);
+ if (createBuilderMethod == null)
+ {
+ throw new ArgumentException("No public static CreateBuilder method declared in " + ClrType.Name);
+ }
+ createBuilderDelegate = ReflectionUtil.CreateStaticUpcastDelegate(createBuilderMethod);
+ }
+
+ /// <summary>
+ /// Creates a message of the appropriate CLR type from the given value,
+ /// which may already be of the right type or may be a dynamic message.
+ /// </summary>
+ private object CoerceType(object value)
+ {
+ ThrowHelper.ThrowIfNull(value, "value");
+ // If it's already of the right type, we're done
+ if (ClrType.IsInstanceOfType(value))
+ {
+ return value;
+ }
+
+ // No... so let's create a builder of the right type, and merge the value in.
+ IMessageLite message = (IMessageLite) value;
+ return CreateBuilder().WeakMergeFrom(message).WeakBuild();
+ }
+
+ public override void SetValue(TBuilder builder, object value)
+ {
+ base.SetValue(builder, CoerceType(value));
+ }
+
+ public override IBuilder CreateBuilder()
+ {
+ return createBuilderDelegate();
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs
new file mode 100644
index 00000000..b9ab7293
--- /dev/null
+++ b/csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs
@@ -0,0 +1,146 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Reflection;
+using Google.ProtocolBuffers.Descriptors;
+
+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<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
+ where TMessage : IMessage<TMessage, TBuilder>
+ where TBuilder : IBuilder<TMessage, TBuilder>
+ {
+ private readonly Type clrType;
+ private readonly Func<TMessage, object> getValueDelegate;
+ private readonly Action<TBuilder, object> setValueDelegate;
+ private readonly Func<TMessage, bool> hasDelegate;
+ private readonly Func<TBuilder, IBuilder> clearDelegate;
+
+ /// <summary>
+ /// The CLR type of the field (int, the enum type, ByteString, the message etc).
+ /// As declared by the property.
+ /// </summary>
+ protected Type ClrType
+ {
+ get { return clrType; }
+ }
+
+ internal SinglePrimitiveAccessor(FieldDescriptor fieldDescriptor, string name, bool supportFieldPresence)
+ {
+ PropertyInfo messageProperty = typeof(TMessage).GetProperty(name, null, ReflectionUtil.EmptyTypes);
+ PropertyInfo builderProperty = typeof(TBuilder).GetProperty(name, null, ReflectionUtil.EmptyTypes);
+ MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
+ if (messageProperty == null || builderProperty == null || clearMethod == null)
+ {
+ throw new ArgumentException("Not all required properties/methods available");
+ }
+
+ if (supportFieldPresence)
+ {
+ PropertyInfo hasProperty = typeof(TMessage).GetProperty("Has" + name);
+ if (hasProperty == null)
+ {
+ throw new ArgumentException("Has properties not available");
+ }
+ hasDelegate = ReflectionUtil.CreateDelegateFunc<TMessage, bool>(hasProperty.GetGetMethod());
+ } else
+ {
+ hasDelegate = message => !GetValue(message).Equals(fieldDescriptor.DefaultValue);
+ }
+
+ clrType = messageProperty.PropertyType;
+ clearDelegate = ReflectionUtil.CreateDelegateFunc<TBuilder, IBuilder>(clearMethod);
+ getValueDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(messageProperty.GetGetMethod());
+ setValueDelegate = ReflectionUtil.CreateDowncastDelegate<TBuilder>(builderProperty.GetSetMethod());
+ }
+
+ public bool Has(TMessage message)
+ {
+ return hasDelegate(message);
+ }
+
+ public void Clear(TBuilder builder)
+ {
+ clearDelegate(builder);
+ }
+
+ /// <summary>
+ /// Only valid for message types - this implementation throws InvalidOperationException.
+ /// </summary>
+ public virtual IBuilder CreateBuilder()
+ {
+ throw new InvalidOperationException();
+ }
+
+ public virtual object GetValue(TMessage message)
+ {
+ return getValueDelegate(message);
+ }
+
+ public virtual void SetValue(TBuilder builder, object value)
+ {
+ setValueDelegate(builder, value);
+ }
+
+ #region Methods only related to repeated values
+
+ public int GetRepeatedCount(TMessage message)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public object GetRepeatedValue(TMessage message, int index)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public void SetRepeated(TBuilder builder, int index, object value)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public void AddRepeated(TBuilder builder, object value)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public object GetRepeatedWrapper(TBuilder builder)
+ {
+ throw new InvalidOperationException();
+ }
+
+ #endregion
+ }
+} \ No newline at end of file