|
@@ -30,9 +30,8 @@
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
-using System;
|
|
|
|
-using System.Linq;
|
|
|
|
using Google.Protobuf.Compatibility;
|
|
using Google.Protobuf.Compatibility;
|
|
|
|
+using System;
|
|
|
|
|
|
namespace Google.Protobuf.Reflection
|
|
namespace Google.Protobuf.Reflection
|
|
{
|
|
{
|
|
@@ -41,20 +40,35 @@ namespace Google.Protobuf.Reflection
|
|
/// </summary>
|
|
/// </summary>
|
|
public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
|
|
public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
|
|
{
|
|
{
|
|
- private readonly FieldDescriptorProto proto;
|
|
|
|
private EnumDescriptor enumType;
|
|
private EnumDescriptor enumType;
|
|
private MessageDescriptor messageType;
|
|
private MessageDescriptor messageType;
|
|
- private readonly MessageDescriptor containingType;
|
|
|
|
- private readonly OneofDescriptor containingOneof;
|
|
|
|
private FieldType fieldType;
|
|
private FieldType fieldType;
|
|
private readonly string propertyName; // Annoyingly, needed in Crosslink.
|
|
private readonly string propertyName; // Annoyingly, needed in Crosslink.
|
|
private IFieldAccessor accessor;
|
|
private IFieldAccessor accessor;
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Get the field's containing message type.
|
|
|
|
+ /// </summary>
|
|
|
|
+ public MessageDescriptor ContainingType { get; }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
|
|
|
|
+ /// </summary>
|
|
|
|
+ public OneofDescriptor ContainingOneof { get; }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// The effective JSON name for this field. This is usually the lower-camel-cased form of the field name,
|
|
|
|
+ /// but can be overridden using the <c>json_name</c> option in the .proto file.
|
|
|
|
+ /// </summary>
|
|
|
|
+ public string JsonName { get; }
|
|
|
|
+
|
|
|
|
+ internal FieldDescriptorProto Proto { get; }
|
|
|
|
+
|
|
internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
|
|
internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
|
|
MessageDescriptor parent, int index, string propertyName)
|
|
MessageDescriptor parent, int index, string propertyName)
|
|
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
|
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
|
{
|
|
{
|
|
- this.proto = proto;
|
|
|
|
|
|
+ Proto = proto;
|
|
if (proto.Type != 0)
|
|
if (proto.Type != 0)
|
|
{
|
|
{
|
|
fieldType = GetFieldTypeFromProtoType(proto.Type);
|
|
fieldType = GetFieldTypeFromProtoType(proto.Type);
|
|
@@ -64,7 +78,7 @@ namespace Google.Protobuf.Reflection
|
|
{
|
|
{
|
|
throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
|
|
throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
|
|
}
|
|
}
|
|
- containingType = parent;
|
|
|
|
|
|
+ ContainingType = parent;
|
|
// OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
|
|
// OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
|
|
if (proto.OneofIndex != -1)
|
|
if (proto.OneofIndex != -1)
|
|
{
|
|
{
|
|
@@ -73,7 +87,7 @@ namespace Google.Protobuf.Reflection
|
|
throw new DescriptorValidationException(this,
|
|
throw new DescriptorValidationException(this,
|
|
$"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
|
|
$"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
|
|
}
|
|
}
|
|
- containingOneof = parent.Oneofs[proto.OneofIndex];
|
|
|
|
|
|
+ ContainingOneof = parent.Oneofs[proto.OneofIndex];
|
|
}
|
|
}
|
|
|
|
|
|
file.DescriptorPool.AddSymbol(this);
|
|
file.DescriptorPool.AddSymbol(this);
|
|
@@ -83,20 +97,14 @@ namespace Google.Protobuf.Reflection
|
|
// We could trust the generated code and check whether the type of the property is
|
|
// We could trust the generated code and check whether the type of the property is
|
|
// a MapField, but that feels a tad nasty.
|
|
// a MapField, but that feels a tad nasty.
|
|
this.propertyName = propertyName;
|
|
this.propertyName = propertyName;
|
|
|
|
+ JsonName = Proto.JsonName == "" ? JsonFormatter.ToCamelCase(Proto.Name) : Proto.JsonName;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// The brief name of the descriptor's target.
|
|
/// The brief name of the descriptor's target.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public override string Name { get { return proto.Name; } }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// The json_name option of the descriptor's target.
|
|
|
|
- /// </summary>
|
|
|
|
- public string JsonName { get { return proto.JsonName == "" ? JsonFormatter.ToCamelCase(proto.Name) : proto.JsonName; } }
|
|
|
|
-
|
|
|
|
- internal FieldDescriptorProto Proto { get { return proto; } }
|
|
|
|
|
|
+ public override string Name => Proto.Name;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns the accessor for this field.
|
|
/// Returns the accessor for this field.
|
|
@@ -116,7 +124,7 @@ namespace Google.Protobuf.Reflection
|
|
/// and this property will return null.
|
|
/// and this property will return null.
|
|
/// </para>
|
|
/// </para>
|
|
/// </remarks>
|
|
/// </remarks>
|
|
- public IFieldAccessor Accessor { get { return accessor; } }
|
|
|
|
|
|
+ public IFieldAccessor Accessor => accessor;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Maps a field type as included in the .proto file to a FieldType.
|
|
/// Maps a field type as included in the .proto file to a FieldType.
|
|
@@ -169,62 +177,32 @@ namespace Google.Protobuf.Reflection
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
|
|
/// Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public bool IsRepeated
|
|
|
|
- {
|
|
|
|
- get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
|
|
|
|
- }
|
|
|
|
|
|
+ public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
|
|
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public bool IsMap
|
|
|
|
- {
|
|
|
|
- get { return fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; }
|
|
|
|
- }
|
|
|
|
|
|
+ public bool IsMap => fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
|
|
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public bool IsPacked
|
|
|
|
- {
|
|
|
|
|
|
+ public bool IsPacked =>
|
|
// Note the || rather than && here - we're effectively defaulting to packed, because that *is*
|
|
// Note the || rather than && here - we're effectively defaulting to packed, because that *is*
|
|
// the default in proto3, which is all we support. We may give the wrong result for the protos
|
|
// the default in proto3, which is all we support. We may give the wrong result for the protos
|
|
// within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
|
|
// within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
|
|
// within the runtime.
|
|
// within the runtime.
|
|
- get { return Proto.Options == null || Proto.Options.Packed; }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Get the field's containing message type.
|
|
|
|
- /// </summary>
|
|
|
|
- public MessageDescriptor ContainingType
|
|
|
|
- {
|
|
|
|
- get { return containingType; }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
|
|
|
|
- /// </summary>
|
|
|
|
- public OneofDescriptor ContainingOneof
|
|
|
|
- {
|
|
|
|
- get { return containingOneof; }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ Proto.Options == null || Proto.Options.Packed;
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns the type of the field.
|
|
/// Returns the type of the field.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public FieldType FieldType
|
|
|
|
- {
|
|
|
|
- get { return fieldType; }
|
|
|
|
- }
|
|
|
|
|
|
+ public FieldType FieldType => fieldType;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns the field number declared in the proto file.
|
|
/// Returns the field number declared in the proto file.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public int FieldNumber
|
|
|
|
- {
|
|
|
|
- get { return Proto.Number; }
|
|
|
|
- }
|
|
|
|
|
|
+ public int FieldNumber => Proto.Number;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Compares this descriptor with another one, ordering in "canonical" order
|
|
/// Compares this descriptor with another one, ordering in "canonical" order
|
|
@@ -234,7 +212,7 @@ namespace Google.Protobuf.Reflection
|
|
/// </summary>
|
|
/// </summary>
|
|
public int CompareTo(FieldDescriptor other)
|
|
public int CompareTo(FieldDescriptor other)
|
|
{
|
|
{
|
|
- if (other.containingType != containingType)
|
|
|
|
|
|
+ if (other.ContainingType != ContainingType)
|
|
{
|
|
{
|
|
throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " +
|
|
throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " +
|
|
"for fields of the same message type.");
|
|
"for fields of the same message type.");
|
|
@@ -337,14 +315,14 @@ namespace Google.Protobuf.Reflection
|
|
|
|
|
|
File.DescriptorPool.AddFieldByNumber(this);
|
|
File.DescriptorPool.AddFieldByNumber(this);
|
|
|
|
|
|
- if (containingType != null && containingType.Proto.Options != null && containingType.Proto.Options.MessageSetWireFormat)
|
|
|
|
|
|
+ if (ContainingType != null && ContainingType.Proto.Options != null && ContainingType.Proto.Options.MessageSetWireFormat)
|
|
{
|
|
{
|
|
throw new DescriptorValidationException(this, "MessageSet format is not supported.");
|
|
throw new DescriptorValidationException(this, "MessageSet format is not supported.");
|
|
}
|
|
}
|
|
- accessor = CreateAccessor(propertyName);
|
|
|
|
|
|
+ accessor = CreateAccessor();
|
|
}
|
|
}
|
|
|
|
|
|
- private IFieldAccessor CreateAccessor(string propertyName)
|
|
|
|
|
|
+ private IFieldAccessor CreateAccessor()
|
|
{
|
|
{
|
|
// If we're given no property name, that's because we really don't want an accessor.
|
|
// If we're given no property name, that's because we really don't want an accessor.
|
|
// (At the moment, that means it's a map entry message...)
|
|
// (At the moment, that means it's a map entry message...)
|
|
@@ -352,10 +330,10 @@ namespace Google.Protobuf.Reflection
|
|
{
|
|
{
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
- var property = containingType.ClrType.GetProperty(propertyName);
|
|
|
|
|
|
+ var property = ContainingType.ClrType.GetProperty(propertyName);
|
|
if (property == null)
|
|
if (property == null)
|
|
{
|
|
{
|
|
- throw new DescriptorValidationException(this, $"Property {propertyName} not found in {containingType.ClrType}");
|
|
|
|
|
|
+ throw new DescriptorValidationException(this, $"Property {propertyName} not found in {ContainingType.ClrType}");
|
|
}
|
|
}
|
|
return IsMap ? new MapFieldAccessor(property, this)
|
|
return IsMap ? new MapFieldAccessor(property, this)
|
|
: IsRepeated ? new RepeatedFieldAccessor(property, this)
|
|
: IsRepeated ? new RepeatedFieldAccessor(property, this)
|