Commit ec8c3955 authored by Jon Skeet's avatar Jon Skeet

Gradually implementing FieldSet

parent b83aee75
...@@ -25,8 +25,8 @@ namespace Google.ProtocolBuffers { ...@@ -25,8 +25,8 @@ namespace Google.ProtocolBuffers {
protected abstract IMessage BuildPartialImpl(); protected abstract IMessage BuildPartialImpl();
protected abstract IBuilder CloneImpl(); protected abstract IBuilder CloneImpl();
protected abstract IMessage DefaultInstanceForTypeImpl { get; } protected abstract IMessage DefaultInstanceForTypeImpl { get; }
protected abstract IBuilder NewBuilderForFieldImpl<TField>(FieldDescriptor field); protected abstract IBuilder NewBuilderForFieldImpl(FieldDescriptor field);
protected abstract IBuilder ClearFieldImpl(); protected abstract IBuilder ClearFieldImpl(FieldDescriptor field);
protected abstract IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value); protected abstract IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value);
#endregion #endregion
...@@ -39,30 +39,30 @@ namespace Google.ProtocolBuffers { ...@@ -39,30 +39,30 @@ namespace Google.ProtocolBuffers {
return BuildPartialImpl(); return BuildPartialImpl();
} }
public IBuilder Clone() { IBuilder IBuilder.Clone() {
return CloneImpl(); return CloneImpl();
} }
public IMessage DefaultInstanceForType { IMessage IBuilder.DefaultInstanceForType {
get { return DefaultInstanceForTypeImpl; } get { return DefaultInstanceForTypeImpl; }
} }
public IBuilder NewBuilderForField<TField>(FieldDescriptor field) { IBuilder IBuilder.NewBuilderForField(FieldDescriptor field) {
return NewBuilderForFieldImpl<TField>(field); return NewBuilderForFieldImpl(field);
} }
public IBuilder ClearField(FieldDescriptor field) { IBuilder IBuilder.ClearField(FieldDescriptor field) {
return ClearFieldImpl(); return ClearFieldImpl(field);
} }
public IBuilder AddRepeatedField(FieldDescriptor field, object value) { IBuilder IBuilder.AddRepeatedField(FieldDescriptor field, object value) {
return AddRepeatedFieldImpl(field, value); return AddRepeatedFieldImpl(field, value);
} }
#endregion #endregion
public IBuilder Clear() { public IBuilder Clear() {
foreach(FieldDescriptor field in AllFields.Keys) { foreach(FieldDescriptor field in AllFields.Keys) {
ClearField(field); ClearFieldImpl(field);
} }
return this; return this;
} }
...@@ -85,7 +85,7 @@ namespace Google.ProtocolBuffers { ...@@ -85,7 +85,7 @@ namespace Google.ProtocolBuffers {
if (field.IsRepeated) { if (field.IsRepeated) {
// Concatenate repeated fields // Concatenate repeated fields
foreach (object element in (IEnumerable) entry.Value) { foreach (object element in (IEnumerable) entry.Value) {
AddRepeatedField(field, element); AddRepeatedFieldImpl(field, element);
} }
} else if (field.MappedType == MappedType.Message) { } else if (field.MappedType == MappedType.Message) {
// Merge singular messages // Merge singular messages
......
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers.Collections {
/// <summary>
/// Non-generic class with generic methods which proxy to the non-generic methods
/// in the generic class.
/// </summary>
public static class Dictionaries {
public static IDictionary<TKey, TValue> AsReadOnly<TKey, TValue> (IDictionary<TKey, TValue> dictionary) {
return dictionary.IsReadOnly ? dictionary : new ReadOnlyDictionary<TKey, TValue>(dictionary);
}
}
}
...@@ -4,18 +4,34 @@ using System.Collections.ObjectModel; ...@@ -4,18 +4,34 @@ using System.Collections.ObjectModel;
using System.Text; using System.Text;
namespace Google.ProtocolBuffers.Collections { namespace Google.ProtocolBuffers.Collections {
public static class Lists {
public static IList<T> AsReadOnly<T>(IList<T> list) {
return Lists<T>.AsReadOnly(list);
}
}
/// <summary> /// <summary>
/// Utilities class for dealing with lists. /// Utilities class for dealing with lists.
/// </summary> /// </summary>
static class Lists<T> { public static class Lists<T> {
static readonly ReadOnlyCollection<T> empty = new ReadOnlyCollection<T>(new T[0]); static readonly ReadOnlyCollection<T> empty = new ReadOnlyCollection<T>(new T[0]);
/// <summary> /// <summary>
/// Returns an immutable empty list. /// Returns an immutable empty list.
/// </summary> /// </summary>
internal static ReadOnlyCollection<T> Empty { public static ReadOnlyCollection<T> Empty {
get { return empty; } get { return empty; }
} }
/// <summary>
/// Returns either the original reference if it's already read-only,
/// or a new ReadOnlyCollection wrapping the original list.
/// </summary>
public static IList<T> AsReadOnly(IList<T> list) {
return list.IsReadOnly ? list : new ReadOnlyCollection<T>(list);
}
} }
} }
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using IEnumerable=System.Collections.IEnumerable;
namespace Google.ProtocolBuffers.Collections {
/// <summary>
/// Read-only wrapper around another dictionary.
/// </summary>
public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
readonly IDictionary<TKey, TValue> wrapped;
public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped) {
this.wrapped = wrapped;
}
public void Add(TKey key, TValue value) {
throw new InvalidOperationException();
}
public bool ContainsKey(TKey key) {
return wrapped.ContainsKey(key);
}
public ICollection<TKey> Keys {
get { return wrapped.Keys; }
}
public bool Remove(TKey key) {
throw new InvalidOperationException();
}
public bool TryGetValue(TKey key, out TValue value) {
return wrapped.TryGetValue(key, out value);
}
public ICollection<TValue> Values {
get { return wrapped.Values; }
}
public TValue this[TKey key] {
get {
return wrapped[key];
}
set {
throw new InvalidOperationException();
}
}
public void Add(KeyValuePair<TKey, TValue> item) {
throw new InvalidOperationException();
}
public void Clear() {
throw new InvalidOperationException();
}
public bool Contains(KeyValuePair<TKey, TValue> item) {
return wrapped.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
wrapped.CopyTo(array, arrayIndex);
}
public int Count {
get { return wrapped.Count; }
}
public bool IsReadOnly {
get { return true; }
}
public bool Remove(KeyValuePair<TKey, TValue> item) {
throw new InvalidOperationException();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
return wrapped.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return ((IEnumerable) wrapped).GetEnumerator();
}
public override bool Equals(object obj) {
return wrapped.Equals(obj);
}
public override int GetHashCode() {
return wrapped.GetHashCode();
}
public override string ToString() {
return wrapped.ToString();
}
}
}

namespace Google.ProtocolBuffers.Descriptors {
public class EnumDescriptor {
}
}
...@@ -2,8 +2,14 @@ ...@@ -2,8 +2,14 @@
namespace Google.ProtocolBuffers.Descriptors { namespace Google.ProtocolBuffers.Descriptors {
public class EnumValueDescriptor { public class EnumValueDescriptor {
private EnumDescriptor enumDescriptor;
public int Number { public int Number {
get { throw new NotImplementedException(); } get { throw new NotImplementedException(); }
} }
public EnumDescriptor EnumDescriptor {
get { return enumDescriptor; }
}
} }
} }
 
using System;
namespace Google.ProtocolBuffers.Descriptors { namespace Google.ProtocolBuffers.Descriptors {
public class FieldDescriptor { public class FieldDescriptor {
private EnumDescriptor enumType;
public bool IsRequired { public bool IsRequired {
get; get;
set; set;
...@@ -25,5 +29,32 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -25,5 +29,32 @@ namespace Google.ProtocolBuffers.Descriptors {
public MessageDescriptor MessageType { get; set; } public MessageDescriptor MessageType { get; set; }
public MessageDescriptor ExtensionScope { get; set; } public MessageDescriptor ExtensionScope { get; set; }
/// <summary>
/// For enum fields, returns the field's type.
/// </summary>
public EnumDescriptor EnumType {
get {
if (MappedType != MappedType.Enum) {
throw new InvalidOperationException("EnumType is only valid for enum fields.");
}
return enumType;
}
}
/// <summary>
/// The default value for this field. For repeated fields
/// this will always be an empty list. For message fields it will
/// always be null. For singular values, it will depend on the descriptor.
/// </summary>
public object DefaultValue
{
get { throw new NotImplementedException(); }
}
public string Name
{
get { throw new NotImplementedException(); }
}
} }
} }
...@@ -9,6 +9,8 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -9,6 +9,8 @@ namespace Google.ProtocolBuffers.Descriptors {
public enum MappedType { public enum MappedType {
Int32, Int32,
Int64, Int64,
UInt32,
UInt64,
Single, Single,
Double, Double,
Boolean, Boolean,
......
using System; namespace Google.ProtocolBuffers.FieldAccess {
using System.Collections.Generic;
using System.Text;
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> internal interface IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage> where TMessage : IMessage<TMessage>
where TBuilder : IBuilder<TMessage> { where TBuilder : IBuilder<TMessage> {
void AddRepeated(IBuilder<TMessage> builder, object value); /// <summary>
/// Indicates whether the specified message contains the field.
/// </summary>
bool Has(IMessage<TMessage> message); bool Has(IMessage<TMessage> message);
/// <summary>
/// Gets the count of the repeated field in the specified message.
/// </summary>
int GetRepeatedCount(IMessage<TMessage> message); int GetRepeatedCount(IMessage<TMessage> message);
void Clear(TBuilder builder);
TBuilder CreateBuilder(); /// <summary>
/// Clears the field in the specified builder.
/// </summary>
/// <param name="builder"></param>
void Clear(IBuilder<TMessage> builder);
/// <summary>
/// Creates a builder for the type of this field (which must be a message field).
/// </summary>
IBuilder CreateBuilder();
/// <summary> /// <summary>
/// Accessor for single fields /// Accessor for single fields
/// </summary> /// </summary>
object this[IMessage<TMessage> message] { get; } object GetValue(IMessage<TMessage> message);
/// <summary> /// <summary>
/// Mutator for single fields /// Mutator for single fields
/// </summary> /// </summary>
object this[IBuilder<TMessage> builder] { set; } void SetValue(IBuilder<TMessage> builder, object value);
/// <summary> /// <summary>
/// Accessor for repeated fields /// Accessor for repeated fields
/// </summary> /// </summary>
object this[IMessage<TMessage> message, int index] { get; } object GetRepeatedValue(IMessage<TMessage> message, int index);
/// <summary> /// <summary>
/// Mutator for repeated fields /// Mutator for repeated fields
/// </summary> /// </summary>
object this[IBuilder<TMessage> builder, int index] { set; } void SetRepeated(IBuilder<TMessage> builder, int index, object value);
/// <summary>
/// Adds the specified value to the field in the given builder.
/// </summary>
void AddRepeated(IBuilder<TMessage> builder, object value);
/// <summary>
/// Returns a read-only wrapper around the value of a repeated field.
/// </summary>
object GetRepeatedWrapper(IBuilder<TMessage> builder);
} }
} }
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.FieldAccess {
internal class SingularFieldAccessor<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage>
where TBuilder : IBuilder<TMessage> {
readonly HasFunction<TMessage> hasProxy;
readonly Action<TBuilder> clearProxy;
internal SingularFieldAccessor(FieldDescriptor descriptor, String pascalCaseName) {
/* Class<? extends GeneratedMessage> messageClass,
Class<? extends GeneratedMessage.Builder> builderClass) {
getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
type = getMethod.getReturnType();
setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
hasMethod =
getMethodOrDie(messageClass, "has" + camelCaseName);
clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName); */
}
public bool Has(IMessage<TMessage> message) {
return false;// hasProxy(message);
}
public void Clear(TBuilder builder) {
// clearProxy(builder);
}
public TBuilder CreateBuilder() {
// return createBuilderProxy(builder);
return default(TBuilder);
}
public object this[IMessage<TMessage> message] {
get { return null;/* getProxy(message);*/ }
}
public object this[IBuilder<TMessage> builder] {
set { /*setProxy(builder, value);*/ }
}
#region Repeated operations (which just throw an exception)
public object this[IMessage<TMessage> message, int index] {
get { throw new InvalidOperationException("Repeated operation called on singular field"); }
}
public object this[IBuilder<TMessage> builder, int index] {
set { throw new InvalidOperationException("Repeated operation called on singular field"); }
}
public int GetRepeatedCount(IMessage<TMessage> message) {
throw new InvalidOperationException("Repeated operation called on singular field");
}
public void AddRepeated(IBuilder<TMessage> builder, object value) {
throw new InvalidOperationException("Repeated operation called on singular field");
}
#endregion
}
}
This diff is collapsed.
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
/// <summary>
/// All generated protocol message builder classes extend this class. It implements
/// most of the IBuilder interface using reflection. Users can ignore this class
/// as an implementation detail.
/// </summary>
public abstract class GeneratedBuilder<TMessage, TBuilder> : AbstractBuilder, IBuilder<TMessage>
where TMessage : GeneratedMessage <TMessage, TBuilder>
where TBuilder : GeneratedBuilder<TMessage, TBuilder>, IBuilder<TMessage> {
/// <summary>
/// Returns the message being built at the moment.
/// </summary>
protected abstract GeneratedMessage<TMessage,TBuilder> MessageBeingBuilt { get; }
public override bool Initialized {
get { return MessageBeingBuilt.IsInitialized; }
}
public override IDictionary<FieldDescriptor, object> AllFields {
get { return MessageBeingBuilt.AllFields; }
}
public override object this[FieldDescriptor field] {
get {
// 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
? MessageBeingBuilt.InternalFieldAccessors[field].GetRepeatedWrapper(this)
: MessageBeingBuilt[field];
}
set {
MessageBeingBuilt.InternalFieldAccessors[field].SetValue(this, value);
}
}
public override MessageDescriptor DescriptorForType {
get { return MessageBeingBuilt.DescriptorForType; }
}
public override int GetRepeatedFieldCount(FieldDescriptor field) {
return MessageBeingBuilt.GetRepeatedFieldCount(field);
}
public override object this[FieldDescriptor field, int index] {
get { return MessageBeingBuilt[field, index]; }
set { MessageBeingBuilt.InternalFieldAccessors[field].SetRepeated(this, index, value); }
}
public override bool HasField(FieldDescriptor field) {
return MessageBeingBuilt.HasField(field);
}
protected override IMessage BuildImpl() {
return Build();
}
protected override IMessage BuildPartialImpl() {
return BuildPartial();
}
protected override IBuilder CloneImpl() {
return Clone();
}
protected override IMessage DefaultInstanceForTypeImpl {
get { return DefaultInstanceForType; }
}
protected override IBuilder NewBuilderForFieldImpl(FieldDescriptor field) {
return NewBuilderForField(field);
}
protected override IBuilder ClearFieldImpl(FieldDescriptor field) {
return ClearField(field);
}
protected override IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value) {
return AddRepeatedField(field, value);
}
public new abstract IBuilder<TMessage> Clear();
public IBuilder<TMessage> MergeFrom(IMessage<TMessage> other) {
throw new NotImplementedException();
}
public abstract IMessage<TMessage> Build();
public abstract IMessage<TMessage> BuildPartial();
public abstract IBuilder<TMessage> Clone();
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(CodedInputStream input) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
public IMessage<TMessage> DefaultInstanceForType {
get { throw new NotImplementedException(); }
}
public IBuilder NewBuilderForField(FieldDescriptor field) {
throw new NotImplementedException();
}
public IBuilder<TMessage> ClearField(FieldDescriptor field) {
MessageBeingBuilt.InternalFieldAccessors[field].Clear(this);
return this;
}
public IBuilder<TMessage> AddRepeatedField(FieldDescriptor field, object value) {
return this;
}
public new IBuilder<TMessage> MergeUnknownFields(UnknownFieldSet unknownFields) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(ByteString data) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(byte[] data) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(System.IO.Stream input) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(System.IO.Stream input, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
}
}
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.Descriptors;
using Google.ProtocolBuffers.FieldAccess; using Google.ProtocolBuffers.FieldAccess;
...@@ -7,7 +8,7 @@ namespace Google.ProtocolBuffers { ...@@ -7,7 +8,7 @@ namespace Google.ProtocolBuffers {
/// <summary> /// <summary>
/// All generated protocol message classes extend this class. It implements /// All generated protocol message classes extend this class. It implements
/// most of the IMessage and IBuilder interfaces using reflection. Users /// most of the IMessage interface using reflection. Users
/// can ignore this class as an implementation detail. /// can ignore this class as an implementation detail.
/// </summary> /// </summary>
public abstract class GeneratedMessage<TMessage, TBuilder> : AbstractMessage, IMessage<TMessage> public abstract class GeneratedMessage<TMessage, TBuilder> : AbstractMessage, IMessage<TMessage>
...@@ -15,7 +16,7 @@ namespace Google.ProtocolBuffers { ...@@ -15,7 +16,7 @@ namespace Google.ProtocolBuffers {
private readonly UnknownFieldSet unknownFields = UnknownFieldSet.DefaultInstance; private readonly UnknownFieldSet unknownFields = UnknownFieldSet.DefaultInstance;
protected abstract FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors { get; } protected internal abstract FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors { get; }
public override MessageDescriptor DescriptorForType { public override MessageDescriptor DescriptorForType {
get { return InternalFieldAccessors.Descriptor; } get { return InternalFieldAccessors.Descriptor; }
...@@ -38,21 +39,22 @@ namespace Google.ProtocolBuffers { ...@@ -38,21 +39,22 @@ namespace Google.ProtocolBuffers {
} }
private IDictionary<FieldDescriptor, Object> GetMutableFieldMap() { private IDictionary<FieldDescriptor, Object> GetMutableFieldMap() {
var ret = new Dictionary<FieldDescriptor, object>();
// Use a SortedList so we'll end up serializing fields in order
var ret = new SortedList<FieldDescriptor, object>();
MessageDescriptor descriptor = DescriptorForType; MessageDescriptor descriptor = DescriptorForType;
foreach (FieldDescriptor field in descriptor.Fields) { foreach (FieldDescriptor field in descriptor.Fields) {
IFieldAccessor<TMessage, TBuilder> accessor = InternalFieldAccessors[field]; IFieldAccessor<TMessage, TBuilder> accessor = InternalFieldAccessors[field];
if ((field.IsRepeated && accessor.GetRepeatedCount(this) != 0) if ((field.IsRepeated && accessor.GetRepeatedCount(this) != 0)
|| accessor.Has(this)) { || accessor.Has(this)) {
ret[field] = accessor[this]; ret[field] = accessor.GetValue(this);
} }
} }
return ret; return ret;
} }
public override IDictionary<FieldDescriptor, object> AllFields { public override IDictionary<FieldDescriptor, object> AllFields {
// FIXME: Make it immutable get { return Dictionaries.AsReadOnly(GetMutableFieldMap()); }
get { return GetMutableFieldMap(); }
} }
public override bool HasField(FieldDescriptor field) { public override bool HasField(FieldDescriptor field) {
...@@ -64,11 +66,11 @@ namespace Google.ProtocolBuffers { ...@@ -64,11 +66,11 @@ namespace Google.ProtocolBuffers {
} }
public override object this[FieldDescriptor field, int index] { public override object this[FieldDescriptor field, int index] {
get { return InternalFieldAccessors[field][this, index]; } get { return InternalFieldAccessors[field].GetRepeatedValue(this, index); }
} }
public override object this[FieldDescriptor field] { public override object this[FieldDescriptor field] {
get { return InternalFieldAccessors[field][this]; } get { return InternalFieldAccessors[field].GetValue(this); }
} }
public override UnknownFieldSet UnknownFields { public override UnknownFieldSet UnknownFields {
......
...@@ -88,7 +88,7 @@ namespace Google.ProtocolBuffers { ...@@ -88,7 +88,7 @@ namespace Google.ProtocolBuffers {
IBuilder MergeFrom(CodedInputStream input); IBuilder MergeFrom(CodedInputStream input);
IBuilder MergeFrom(CodedInputStream codedInputStream, ExtensionRegistry extensionRegistry); IBuilder MergeFrom(CodedInputStream codedInputStream, ExtensionRegistry extensionRegistry);
IMessage DefaultInstanceForType { get; } IMessage DefaultInstanceForType { get; }
IBuilder NewBuilderForField<TField>(FieldDescriptor field); IBuilder NewBuilderForField(FieldDescriptor field);
IBuilder ClearField(FieldDescriptor field); IBuilder ClearField(FieldDescriptor field);
IBuilder AddRepeatedField(FieldDescriptor field, object value); IBuilder AddRepeatedField(FieldDescriptor field, object value);
IBuilder MergeUnknownFields(UnknownFieldSet unknownFields); IBuilder MergeUnknownFields(UnknownFieldSet unknownFields);
...@@ -191,7 +191,7 @@ namespace Google.ProtocolBuffers { ...@@ -191,7 +191,7 @@ namespace Google.ProtocolBuffers {
/// Messages built with this can then be passed to the various mutation properties /// Messages built with this can then be passed to the various mutation properties
/// and methods. /// and methods.
/// </summary> /// </summary>
new IBuilder<TField> NewBuilderForField<TField>(FieldDescriptor field) where TField : IMessage<TField>; //new IBuilder<TField> NewBuilderForField<TField>(FieldDescriptor field) where TField : IMessage<TField>;
/// <summary> /// <summary>
/// Clears the field. This is exactly equivalent to calling the generated /// Clears the field. This is exactly equivalent to calling the generated
......
...@@ -42,7 +42,10 @@ ...@@ -42,7 +42,10 @@
<Compile Include="ByteString.cs" /> <Compile Include="ByteString.cs" />
<Compile Include="CodedInputStream.cs" /> <Compile Include="CodedInputStream.cs" />
<Compile Include="CodedOutputStream.cs" /> <Compile Include="CodedOutputStream.cs" />
<Compile Include="Collections\Dictionaries.cs" />
<Compile Include="Collections\Lists.cs" /> <Compile Include="Collections\Lists.cs" />
<Compile Include="Collections\ReadOnlyDictionary.cs" />
<Compile Include="Descriptors\EnumDescriptor.cs" />
<Compile Include="Descriptors\EnumValueDescriptor.cs" /> <Compile Include="Descriptors\EnumValueDescriptor.cs" />
<Compile Include="Descriptors\FieldDescriptor.cs" /> <Compile Include="Descriptors\FieldDescriptor.cs" />
<Compile Include="Descriptors\FieldType.cs" /> <Compile Include="Descriptors\FieldType.cs" />
...@@ -53,8 +56,8 @@ ...@@ -53,8 +56,8 @@
<Compile Include="FieldAccess\Delegates.cs" /> <Compile Include="FieldAccess\Delegates.cs" />
<Compile Include="FieldAccess\IFieldAccessor.cs" /> <Compile Include="FieldAccess\IFieldAccessor.cs" />
<Compile Include="FieldAccess\FieldAccessorTable.cs" /> <Compile Include="FieldAccess\FieldAccessorTable.cs" />
<Compile Include="FieldAccess\SingularFieldAccessor.cs" />
<Compile Include="FieldSet.cs" /> <Compile Include="FieldSet.cs" />
<Compile Include="GeneratedBuilder.cs" />
<Compile Include="GeneratedExtension.cs" /> <Compile Include="GeneratedExtension.cs" />
<Compile Include="GeneratedMessage.cs" /> <Compile Include="GeneratedMessage.cs" />
<Compile Include="IBuilder.cs" /> <Compile Include="IBuilder.cs" />
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers { namespace Google.ProtocolBuffers {
public class UnknownFieldSet { public class UnknownFieldSet {
...@@ -48,10 +49,10 @@ namespace Google.ProtocolBuffers { ...@@ -48,10 +49,10 @@ namespace Google.ProtocolBuffers {
} }
/// <summary> /// <summary>
/// Creates and returns a copy of the mapping from field numbers to values. /// Returns a read-only view of the mapping from field numbers to values.
/// </summary> /// </summary>
public IDictionary<int, UnknownField> FieldDictionary { public IDictionary<int, UnknownField> FieldDictionary {
get { return new Dictionary<int, UnknownField>(fields); } get { return Dictionaries.AsReadOnly(fields); }
} }
/// <summary> /// <summary>
...@@ -195,7 +196,11 @@ namespace Google.ProtocolBuffers { ...@@ -195,7 +196,11 @@ namespace Google.ProtocolBuffers {
public class Builder public class Builder
{ {
private Dictionary<int, UnknownField> fields = new Dictionary<int, UnknownField>(); /// <summary>
/// Mapping from number to field. Note that by using a SortedList we ensure
/// that the fields will be serialized in ascending order.
/// </summary>
private IDictionary<int, UnknownField> fields = new SortedList<int, UnknownField>();
// Optimization: We keep around a builder for the last field that was // Optimization: We keep around a builder for the last field that was
// modified so that we can efficiently add to it multiple times in a // modified so that we can efficiently add to it multiple times in a
......
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