Skip to content

Commit

Permalink
Helper method on Any to allow an any to be unpacked more easily
Browse files Browse the repository at this point in the history
We already have the TypeRegistry abstraction for JSON parsing, so it lends itself well to this.

Note that this is much more useful than it would have been before C# gained pattern matching support: it's easy to imagine a switch statement/expression using pattern matching with the result of this, with cases for a set of known message types, for example.
  • Loading branch information
jskeet committed Mar 29, 2022
1 parent 43bb1bf commit f9729ec
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
30 changes: 29 additions & 1 deletion csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using Google.Protobuf.Reflection;
using Google.Protobuf.TestProtos;
using NUnit.Framework;

using System.Linq;
using UnitTest.Issues.TestProtos;

namespace Google.Protobuf.WellKnownTypes
{
public class AnyTest
Expand Down Expand Up @@ -148,10 +151,35 @@ public void IsWrongType()
Assert.False(any.Is(TestOneof.Descriptor));
}

[Test]
public void IsRightType()
{
var any = Any.Pack(SampleMessages.CreateFullTestAllTypes());
Assert.True(any.Is(TestAllTypes.Descriptor));
}

[Test]
public void UnpackMessage()
{
var messages = new IMessage[]
{
SampleMessages.CreateFullTestAllTypes(),
new TestWellKnownTypes { BoolField = true },
new MoreString { Data = { "x" } },
new MoreBytes { Data = ByteString.CopyFromUtf8("xyz") },
new ReservedNames { Descriptor_ = 10 }
};
var anyMessages = messages.Select(Any.Pack);

// The type registry handles the first four of the packed messages, but not the final one.
var registry = TypeRegistry.FromFiles(
UnittestWellKnownTypesReflection.Descriptor,
UnittestWellKnownTypesReflection.Descriptor,
UnittestProto3Reflection.Descriptor);
var unpacked = anyMessages.Select(any => any.UnpackMessage(registry)).ToList();
var expected = (IMessage[]) messages.Clone();
expected[4] = null;
Assert.AreEqual(expected, unpacked);
}
}
}
20 changes: 20 additions & 0 deletions csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,26 @@ public bool Is(MessageDescriptor descriptor)
return true;
}

/// <summary>
/// Attempts to unpack the content of this Any message into one of the message types
/// in the given type registry, based on the type URL.
/// </summary>
/// <param name="registry">The type registry to consult for messages.</param>
/// <returns>The unpacked message, or <c>null</c> if no matching message was found.</returns>
public IMessage UnpackMessage(TypeRegistry registry)
{
string typeName = GetTypeName(TypeUrl);
MessageDescriptor descriptor = registry.Find(typeName);
if (descriptor == null)
{
return null;
}

var message = descriptor.Parser.CreateTemplate();
message.MergeFrom(Value);
return message;
}

/// <summary>
/// Packs the specified message into an Any message using a type URL prefix of "type.googleapis.com".
/// </summary>
Expand Down

0 comments on commit f9729ec

Please sign in to comment.