diff options
Diffstat (limited to 'csharp/src/ProtocolBuffers/FieldAccess/SingleFieldAccessor.cs')
-rw-r--r-- | csharp/src/ProtocolBuffers/FieldAccess/SingleFieldAccessor.cs | 64 |
1 files changed, 17 insertions, 47 deletions
diff --git a/csharp/src/ProtocolBuffers/FieldAccess/SingleFieldAccessor.cs b/csharp/src/ProtocolBuffers/FieldAccess/SingleFieldAccessor.cs index 7a8f726e..cdc89e8d 100644 --- a/csharp/src/ProtocolBuffers/FieldAccess/SingleFieldAccessor.cs +++ b/csharp/src/ProtocolBuffers/FieldAccess/SingleFieldAccessor.cs @@ -39,76 +39,46 @@ namespace Google.Protobuf.FieldAccess /// <summary> /// Accessor for single fields. /// </summary> - /// <typeparam name="T">The type of message containing the field.</typeparam> - internal sealed class SingleFieldAccessor<T> : FieldAccessorBase<T> where T : IMessage<T> + internal sealed class SingleFieldAccessor : FieldAccessorBase { // All the work here is actually done in the constructor - it creates the appropriate delegates. // There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive) // and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default // values. - private readonly Action<T, object> setValueDelegate; - private readonly Action<T> clearDelegate; - private readonly Func<T, bool> hasValueDelegate; + private readonly Action<object, object> setValueDelegate; + private readonly Action<object> clearDelegate; - internal SingleFieldAccessor(FieldDescriptor descriptor, string name, bool supportsFieldPresence) : base(name) + internal SingleFieldAccessor(Type type, string propertyName, FieldDescriptor descriptor) : base(type, propertyName, descriptor) { - PropertyInfo property = typeof(T).GetProperty(name); + PropertyInfo property = type.GetProperty(propertyName); // We know there *is* such a property, or the base class constructor would have thrown. We should be able to write // to it though. if (!property.CanWrite) { throw new ArgumentException("Not all required properties/methods available"); } - setValueDelegate = ReflectionUtil.CreateDowncastDelegate<T>(property.GetSetMethod()); + setValueDelegate = ReflectionUtil.CreateActionObjectObject(property.GetSetMethod()); var clrType = property.PropertyType; + + // TODO: What should clear on a oneof member do? Clear the oneof? - if (typeof(IMessage).IsAssignableFrom(clrType)) - { - // Message types are simple - we only need to detect nullity. - clearDelegate = message => SetValue(message, null); - hasValueDelegate = message => GetValue(message) == null; - } - - if (supportsFieldPresence) - { - // Proto2: we expect a HasFoo property and a ClearFoo method. - // For strings and byte arrays, setting the property to null would have the equivalent effect, - // but we generate the method for consistency, which makes this simpler. - PropertyInfo hasProperty = typeof(T).GetProperty("Has" + name); - MethodInfo clearMethod = typeof(T).GetMethod("Clear" + name); - if (hasProperty == null || clearMethod == null || !hasProperty.CanRead) - { - throw new ArgumentException("Not all required properties/methods available"); - } - hasValueDelegate = ReflectionUtil.CreateDelegateFunc<T, bool>(hasProperty.GetGetMethod()); - clearDelegate = ReflectionUtil.CreateDelegateAction<T>(clearMethod); - } - else - { - /* - // TODO(jonskeet): Reimplement. We need a better way of working out default values. - // Proto3: for field detection, we just need the default value of the field (0, "", byte[0] etc) - // To clear a field, we set the value to that default. - object defaultValue = descriptor.DefaultValue; - hasValueDelegate = message => GetValue(message).Equals(defaultValue); - clearDelegate = message => SetValue(message, defaultValue); - */ - } - } - - public override bool HasValue(T message) - { - return hasValueDelegate(message); + // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.) + object defaultValue = + typeof(IMessage).IsAssignableFrom(clrType) ? null + : clrType == typeof(string) ? "" + : clrType == typeof(ByteString) ? ByteString.Empty + : Activator.CreateInstance(clrType); + clearDelegate = message => SetValue(message, defaultValue); } - public override void Clear(T message) + public override void Clear(object message) { clearDelegate(message); } - public override void SetValue(T message, object value) + public override void SetValue(object message, object value) { setValueDelegate(message, value); } |