Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper method on Any to allow an any to be unpacked more easily #9695

Merged
merged 1 commit into from
May 13, 2022

Conversation

jskeet
Copy link
Contributor

@jskeet jskeet commented Mar 29, 2022

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.

@jskeet
Copy link
Contributor Author

jskeet commented Mar 29, 2022

Note: this is very tentative at the moment. It works, but I'll need to check with the protobuf team whether this is a pattern used elsewhere, and whether there's a different name I should use for consistency, etc.

@jtattermusch
Copy link
Contributor

Is this ready for review? Please let me know once it is. I think an example to demonstrate the use case would be useful.

@jskeet
Copy link
Contributor Author

jskeet commented Mar 30, 2022

Yes, it's ready for review, in terms of the code - just not ready in terms of needing to check it with Protobuf team members. Will write some sample code here as a comment after a meeting...

@jskeet
Copy link
Contributor Author

jskeet commented Mar 30, 2022

Okay, here's a concrete example, based on [error details](https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto( and status:

var status = /* obtain the status from an RpcException */;
var typeRegistry = /* a type registry including error_details.proto */;
foreach (var detail in status.Details)
{
    switch (detail.UnpackMessage(typeRegistry))
    {
        case ErrorInfo errorInfo:
            Console.WriteLine($"Error info: {errorInfo.Domain} / {errorInfo.Reason}");
            Console.WriteLine($"Metadata keys: {string.Join(", ", errorInfo.Metadata.Keys)}");
            break;
        case LocalizedMessage lm:
            Console.WriteLine($"Localized message ({lm.locale}): {lm.Message}");
            break;
        case Help help:
            Console.WriteLine($"Help, first link: {help.Links.FirstOrDefault().Url}");
            break;
        case BadRequest badReq:
            Console.WriteLine($"Bad request; broken fields: {string.Join(", ", badReq.FieldViolations.Select(fv => fv.Field))}");
            break;
        case IMessage unhandled:
            Console.WriteLine($"Known but unhandled message: {unhandled}");
            break;
        default:
            Console.WriteLine($"Unknown detail type URL: {detail.TypeUrl}");
            break;
    }
}

(This code hasn't been compiled or tested, so may have some typos, but should get across the utility of not having to call Any.TryUnpack lots of times.)

Copy link
Contributor

@jtattermusch jtattermusch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems useful. LGTM for the C# code. Please check the general idea with the protobuf team.

/// </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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why UnpackMessage instead of Unpack?

Copy link
Contributor

@JamesNK JamesNK Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'm guessing having Unpack overloads with different return types could be confusing)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precisely your guess. Although that doesn't mean I'm unwilling to discuss it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how much president there is for different return types in overloads from .NET APIs or ASP.NET Core APIs. Is there is an example of a popular API that has different return types? I can't think of one off the top of my head.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some precedent for this, in terms of Enum.Parse vs Enum.Parse<TEnum>. But it's relatively rare.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO I'd name them the same. They both unpack a message, just the arguments to do it (generic vs TypeRegistry) are different.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to Unpack. Both of these methods "unpack a message" as James said, so I find it more confusing for only one of them to be named "UnpackMessage". I supposed something like "UnpackFromTypeRegistry" would work too, but that seems a bit verbose

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to Unpack.

Copy link

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines 176 to 177
UnittestWellKnownTypesReflection.Descriptor,
UnittestWellKnownTypesReflection.Descriptor,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these two the same?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, isn't this redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. I think when I originally wrote the test I did have some reason in mind, but it's gone now :)

@mkruskal-google mkruskal-google self-requested a review April 13, 2022 19:26
/// </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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to Unpack. Both of these methods "unpack a message" as James said, so I find it more confusing for only one of them to be named "UnpackMessage". I supposed something like "UnpackFromTypeRegistry" would work too, but that seems a bit verbose

Comment on lines 176 to 177
UnittestWellKnownTypesReflection.Descriptor,
UnittestWellKnownTypesReflection.Descriptor,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, isn't this redundant?

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.
@mkruskal-google
Copy link
Member

This LGTM, but let's go through a lightweight Tier 2 review first since this is a public API change

@jskeet
Copy link
Contributor Author

jskeet commented Apr 14, 2022

This LGTM, but let's go through a lightweight Tier 2 review first since this is a public API change

Yup. Will do that on Tuesday. (UK has public holidays Friday/Monday.)

@jskeet jskeet merged commit c32d7ec into protocolbuffers:main May 13, 2022
@jskeet jskeet deleted the unpack-registry branch May 13, 2022 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants