diff --git a/csharp/src/Google.Protobuf/FieldMaskTree.cs b/csharp/src/Google.Protobuf/FieldMaskTree.cs index 36c823bed..ff9e08877 100644 --- a/csharp/src/Google.Protobuf/FieldMaskTree.cs +++ b/csharp/src/Google.Protobuf/FieldMaskTree.cs @@ -120,7 +120,8 @@ namespace Google.Protobuf return this; } - if (!node.Children.TryGetValue(part, out var childNode)) + Node childNode; + if (!node.Children.TryGetValue(part, out childNode)) { createNewBranch = true; childNode = new Node(); @@ -361,4 +362,4 @@ namespace Google.Protobuf } } } -} \ No newline at end of file +} diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 8ea3818a4..e65d3969d 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -5,6 +5,7 @@ Copyright 2015, Google Inc. Google Protocol Buffers 3.6.1 + 6 Google Inc. netstandard1.0;net45 true diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs index 6d4520c0b..992b792ad 100644 --- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs @@ -98,64 +98,65 @@ namespace Google.Protobuf.Reflection } } return dictionary; + } - IDescriptor FindDescriptorForPath(IList path) + private IDescriptor FindDescriptorForPath(IList path) + { + // All complete declarations have an even, non-empty path length + // (There can be an empty path for a descriptor declaration, but that can't have any comments, + // so we currently ignore it.) + if (path.Count == 0 || (path.Count & 1) != 0) { - // All complete declarations have an even, non-empty path length - // (There can be an empty path for a descriptor declaration, but that can't have any comments, - // so we currently ignore it.) - if (path.Count == 0 || (path.Count & 1) != 0) - { - return null; - } - IReadOnlyList topLevelList = GetNestedDescriptorListForField(path[0]); - DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]); - - for (int i = 2; current != null && i < path.Count; i += 2) - { - var list = current.GetNestedDescriptorListForField(path[i]); - current = GetDescriptorFromList(list, path[i + 1]); - } - return current; + return null; } + IReadOnlyList topLevelList = GetNestedDescriptorListForField(path[0]); + DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]); - DescriptorBase GetDescriptorFromList(IReadOnlyList list, int index) + for (int i = 2; current != null && i < path.Count; i += 2) { - // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor - // field. - if (list == null) - { - return null; - } - // We *could* return null to silently continue, but this is basically data corruption. - if (index < 0 || index >= list.Count) - { - // We don't have much extra information to give at this point unfortunately. If this becomes a problem, - // we can pass in the complete path and report that and the file name. - throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range"); - } - return list[index]; + var list = current.GetNestedDescriptorListForField(path[i]); + current = GetDescriptorFromList(list, path[i + 1]); } + return current; + } - IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) + private DescriptorBase GetDescriptorFromList(IReadOnlyList list, int index) + { + // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor + // field. + if (list == null) { - switch (fieldNumber) - { - case FileDescriptorProto.ServiceFieldNumber: - return (IReadOnlyList) Services; - case FileDescriptorProto.MessageTypeFieldNumber: - return (IReadOnlyList) MessageTypes; - case FileDescriptorProto.EnumTypeFieldNumber: - return (IReadOnlyList) EnumTypes; - default: - return null; - } + return null; + } + // We *could* return null to silently continue, but this is basically data corruption. + if (index < 0 || index >= list.Count) + { + // We don't have much extra information to give at this point unfortunately. If this becomes a problem, + // we can pass in the complete path and report that and the file name. + throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range"); + } + return list[index]; + } + + private IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) + { + switch (fieldNumber) + { + case FileDescriptorProto.ServiceFieldNumber: + return (IReadOnlyList) Services; + case FileDescriptorProto.MessageTypeFieldNumber: + return (IReadOnlyList) MessageTypes; + case FileDescriptorProto.EnumTypeFieldNumber: + return (IReadOnlyList) EnumTypes; + default: + return null; } } internal DescriptorDeclaration GetDeclaration(IDescriptor descriptor) { - declarations.Value.TryGetValue(descriptor, out var declaration); + DescriptorDeclaration declaration; + declarations.Value.TryGetValue(descriptor, out declaration); return declaration; } @@ -191,7 +192,8 @@ namespace Google.Protobuf.Reflection throw new DescriptorValidationException(@this, "Invalid public dependency index."); } string name = proto.Dependency[index]; - if (!nameToFileMap.TryGetValue(name, out var file)) + FileDescriptor file; + if (!nameToFileMap.TryGetValue(name, out file)) { if (!allowUnknownDependencies) { @@ -414,7 +416,8 @@ namespace Google.Protobuf.Reflection var dependencies = new List(); foreach (var dependencyName in proto.Dependency) { - if (!descriptorsByName.TryGetValue(dependencyName, out var dependency)) + FileDescriptor dependency; + if (!descriptorsByName.TryGetValue(dependencyName, out dependency)) { throw new ArgumentException($"Dependency missing: {dependencyName}"); } diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs index d541570fd..5872ee20d 100644 --- a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs +++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs @@ -60,13 +60,22 @@ namespace Google.Protobuf.Reflection if (descriptor.File.Proto.Syntax == "proto2") { MethodInfo hasMethod = property.DeclaringType.GetRuntimeProperty("Has" + property.Name).GetMethod; - hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod ?? throw new ArgumentException("Not all required properties/methods are available")); + if (hasMethod == null) { + throw new ArgumentException("Not all required properties/methods are available"); + } + hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod); MethodInfo clearMethod = property.DeclaringType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes); - clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod ?? throw new ArgumentException("Not all required properties/methods are available")); + if (clearMethod == null) { + throw new ArgumentException("Not all required properties/methods are available"); + } + clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod); } else { - hasDelegate = (_) => throw new InvalidOperationException("HasValue is not implemented for proto3 fields"); var clrType = property.PropertyType; + hasDelegate = message => { + throw new InvalidOperationException("HasValue is not implemented for proto3 fields"); + }; + var clrType = property.PropertyType; // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.) object defaultValue = diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs index a92519745..2f5172f1c 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs @@ -308,7 +308,7 @@ namespace Google.Protobuf.WellKnownTypes /// true if the two timestamps refer to the same nanosecond public static bool operator ==(Timestamp a, Timestamp b) { - return ReferenceEquals(a, b) || (a is null ? (b is null ? true : false) : a.Equals(b)); + return ReferenceEquals(a, b) || (ReferenceEquals(a, null) ? (ReferenceEquals(b, null) ? true : false) : a.Equals(b)); } ///