1ffe3c632Sopenharmony_ciAs part of the 3.10 release of Google.Protobuf, experimental proto2 support has been released. This document outlines the new changes brought about to include proto2 support. This does not break existing proto3 support and users may continue to use proto3 features without changing their current code. Again the generated code and public API associated with proto2 is experimental and subject to change in the future. APIs for proto2 may be added, removed, or adjusted as feedback is received.
2ffe3c632Sopenharmony_ciGenerated code for proto2 may also be modified by adding, removing, or adjusting APIs as feedback is received.
3ffe3c632Sopenharmony_ci
4ffe3c632Sopenharmony_ci### Enabling proto2 features
5ffe3c632Sopenharmony_ci
6ffe3c632Sopenharmony_ciFor information about specific proto2 features, please read the [proto2 language guide](https://developers.google.com/protocol-buffers/docs/proto).
7ffe3c632Sopenharmony_ci
8ffe3c632Sopenharmony_ciMuch like other languages, proto2 features are used with proto2 files with the syntax declaration `syntax = "proto2";`. However, please note, proto3 is still the recommended version of protobuf and proto2 support is meant for legacy system interop and advanced uses.
9ffe3c632Sopenharmony_ci
10ffe3c632Sopenharmony_ci# Generated code
11ffe3c632Sopenharmony_ci
12ffe3c632Sopenharmony_ci### Messages
13ffe3c632Sopenharmony_ci
14ffe3c632Sopenharmony_ciMessages in proto2 files are very similar to their proto3 counterparts. They expose the usual property for getting and setting,  but they also include properties and methods to handle field presence.
15ffe3c632Sopenharmony_ci
16ffe3c632Sopenharmony_ciFor `optional`/`required` field XYZ, a `HasXYZ` property is included for checking presence and a `ClearXYZ` method is included for clearing the value.
17ffe3c632Sopenharmony_ci
18ffe3c632Sopenharmony_ci```proto
19ffe3c632Sopenharmony_cimessage Foo {
20ffe3c632Sopenharmony_ci    optional Bar bar = 1;
21ffe3c632Sopenharmony_ci    required Baz baz = 2;
22ffe3c632Sopenharmony_ci}
23ffe3c632Sopenharmony_ci```
24ffe3c632Sopenharmony_ci```cs
25ffe3c632Sopenharmony_civar foo = new Foo();
26ffe3c632Sopenharmony_ciAssert.IsNull(foo.Bar);
27ffe3c632Sopenharmony_ciAssert.False(foo.HasBar);
28ffe3c632Sopenharmony_cifoo.Bar = new Bar();
29ffe3c632Sopenharmony_ciAssert.True(foo.HasBar);
30ffe3c632Sopenharmony_cifoo.ClearBar();
31ffe3c632Sopenharmony_ci```
32ffe3c632Sopenharmony_ci
33ffe3c632Sopenharmony_ci### Messages with extension ranges
34ffe3c632Sopenharmony_ci
35ffe3c632Sopenharmony_ciMessages which define extension ranges implement the `IExtendableMessage` interface as shown below.
36ffe3c632Sopenharmony_ciSee inline comments for more info.
37ffe3c632Sopenharmony_ci
38ffe3c632Sopenharmony_ci```cs
39ffe3c632Sopenharmony_cipublic interface IExtendableMessage<T> : IMessage<T> where T : IExtendableMessage<T>
40ffe3c632Sopenharmony_ci{
41ffe3c632Sopenharmony_ci    // Gets the value of a single value extension. If the extension isn't present, this returns the default value.
42ffe3c632Sopenharmony_ci    TValue GetExtension<TValue>(Extension<T, TValue> extension);
43ffe3c632Sopenharmony_ci    // Gets the value of a repeated extension. If the extension hasn't been set, this returns null to prevent unnecessary allocations.
44ffe3c632Sopenharmony_ci    RepeatedField<TValue> GetExtension<TValue>(RepeatedExtension<T, TValue> extension);
45ffe3c632Sopenharmony_ci    // Gets the value of a repeated extension. This will initialize the value of the repeated field and will never return null.
46ffe3c632Sopenharmony_ci    RepeatedField<TValue> GetOrInitializeExtension<TValue>(RepeatedExtension<T, TValue> extension);
47ffe3c632Sopenharmony_ci    // Sets the value of the extension
48ffe3c632Sopenharmony_ci    void SetExtension<TValue>(Extension<T, TValue> extension, TValue value);
49ffe3c632Sopenharmony_ci    // Returns whether the extension is present in the message
50ffe3c632Sopenharmony_ci    bool HasExtension<TValue>(Extension<T, TValue> extension);
51ffe3c632Sopenharmony_ci    // Clears the value of the extension, removing it from the message
52ffe3c632Sopenharmony_ci    void ClearExtension<TValue>(Extension<T, TValue> extension);
53ffe3c632Sopenharmony_ci    // Clears the value of the repeated extension, removing it from the message. Calling GetExtension after this will always return null.
54ffe3c632Sopenharmony_ci    void ClearExtension<TValue>(RepeatedExtension<T, TValue> extension);
55ffe3c632Sopenharmony_ci}
56ffe3c632Sopenharmony_ci```
57ffe3c632Sopenharmony_ci
58ffe3c632Sopenharmony_ci### Extensions
59ffe3c632Sopenharmony_ci
60ffe3c632Sopenharmony_ciExtensions are generated in static containers like reflection classes and type classes. 
61ffe3c632Sopenharmony_ciFor example for a file called `foo.proto` containing extensions in the file scope, a 
62ffe3c632Sopenharmony_ci`FooExtensions` class is created containing the extensions defined in the file scope.
63ffe3c632Sopenharmony_ciFor easy access, this class can be used with `using static` to bring all extensions into scope.
64ffe3c632Sopenharmony_ci
65ffe3c632Sopenharmony_ci```proto
66ffe3c632Sopenharmony_cioption csharp_namespace = "FooBar";
67ffe3c632Sopenharmony_ciextend Foo {
68ffe3c632Sopenharmony_ci    optional Baz foo_ext = 124;
69ffe3c632Sopenharmony_ci}
70ffe3c632Sopenharmony_cimessage Baz {
71ffe3c632Sopenharmony_ci    extend Foo {
72ffe3c632Sopenharmony_ci        repeated Baz repeated_foo_ext = 125;
73ffe3c632Sopenharmony_ci    }
74ffe3c632Sopenharmony_ci}
75ffe3c632Sopenharmony_ci```
76ffe3c632Sopenharmony_ci```cs
77ffe3c632Sopenharmony_cipublic static partial class FooExtensions {
78ffe3c632Sopenharmony_ci    public static readonly Extension<Foo, Baz> FooExt = /* initialization */;
79ffe3c632Sopenharmony_ci}
80ffe3c632Sopenharmony_ci
81ffe3c632Sopenharmony_cipublic partial class Baz {
82ffe3c632Sopenharmony_ci    public partial static class Extensions {
83ffe3c632Sopenharmony_ci        public static readonly RepeatedExtension<Foo, Baz> RepeatedFooExt = /* initialization */;
84ffe3c632Sopenharmony_ci    }
85ffe3c632Sopenharmony_ci}
86ffe3c632Sopenharmony_ci```
87ffe3c632Sopenharmony_ci```cs
88ffe3c632Sopenharmony_ciusing static FooBar.FooExtensions;
89ffe3c632Sopenharmony_ciusing static FooBar.Baz.Extensions;
90ffe3c632Sopenharmony_ci
91ffe3c632Sopenharmony_civar foo = new Foo();
92ffe3c632Sopenharmony_cifoo.SetExtension(FooExt, new Baz());
93ffe3c632Sopenharmony_cifoo.GetOrInitializeExtension(RepeatedFooExt).Add(new Baz());
94ffe3c632Sopenharmony_ci```
95ffe3c632Sopenharmony_ci
96ffe3c632Sopenharmony_ci# APIs
97ffe3c632Sopenharmony_ci
98ffe3c632Sopenharmony_ci### Message initialization
99ffe3c632Sopenharmony_ci
100ffe3c632Sopenharmony_ciInitialization refers to checking the status of required fields in a proto2 message. If a message is uninitialized, not all required fields are set in either the message itself or any of its submessages. In other languages, missing required fields throw errors depending on the merge method used. This could cause unforseen errors at runtime if the incorrect method is used. 
101ffe3c632Sopenharmony_ciHowever, in this implementation, parsers and input streams don't check messages for initialization on their own and throw errors. Instead it's up to you to handle messages with missing required fields in whatever way you see fit.
102ffe3c632Sopenharmony_ciChecking message initialization can be done manually via the `IsInitialized` extension method in `MessageExtensions`.
103ffe3c632Sopenharmony_ci
104ffe3c632Sopenharmony_ci### Extension registries
105ffe3c632Sopenharmony_ci
106ffe3c632Sopenharmony_ciJust like in Java, extension registries can be constructed to parse extensions when reading new messages
107ffe3c632Sopenharmony_cifrom input streams. The API is fairly similar to the Java API with some added bonuses with C# syntax sugars.
108ffe3c632Sopenharmony_ci
109ffe3c632Sopenharmony_ci```proto
110ffe3c632Sopenharmony_cimessage Baz {
111ffe3c632Sopenharmony_ci    extend Foo {
112ffe3c632Sopenharmony_ci        optional Baz foo_ext = 124;
113ffe3c632Sopenharmony_ci    }
114ffe3c632Sopenharmony_ci}
115ffe3c632Sopenharmony_ci```
116ffe3c632Sopenharmony_ci```cs
117ffe3c632Sopenharmony_civar registry = new ExtensionRegistry() 
118ffe3c632Sopenharmony_ci{ 
119ffe3c632Sopenharmony_ci    Baz.Extensions.FooExt
120ffe3c632Sopenharmony_ci};
121ffe3c632Sopenharmony_civar foo = Foo.Factory.WithExtensionRegistry(registry).ParseFrom(input);
122ffe3c632Sopenharmony_ciAssert.True(foo.HasExtension(Bas.Extensions.FooExt));
123ffe3c632Sopenharmony_civar fooNoRegistry = Foo.Factory.ParseFrom(input);
124ffe3c632Sopenharmony_ciAssert.False(foo.HasExtension(Bas.Extensions.FooExt));
125ffe3c632Sopenharmony_ci```
126ffe3c632Sopenharmony_ci
127ffe3c632Sopenharmony_ci### Custom options
128ffe3c632Sopenharmony_ci
129ffe3c632Sopenharmony_ciDue to their limited use and lack of type safety, the original `CustomOptions` APIs are now deprecated. Using the new generated extension identifiers, you can access extensions safely through the GetOption APIs. Note that cloneable values such as 
130ffe3c632Sopenharmony_cirepeated fields and messages will be deep cloned.
131ffe3c632Sopenharmony_ci
132ffe3c632Sopenharmony_ciExample based on custom options usage example [here](https://github.com/protocolbuffers/protobuf/issues/5007#issuecomment-411604515).
133ffe3c632Sopenharmony_ci```cs
134ffe3c632Sopenharmony_ciforeach (var service in input.Services)
135ffe3c632Sopenharmony_ci{
136ffe3c632Sopenharmony_ci    Console.WriteLine($"  {service.Name}");
137ffe3c632Sopenharmony_ci    foreach (var method in service.Methods)
138ffe3c632Sopenharmony_ci    {
139ffe3c632Sopenharmony_ci        var rule = method.GetOption(AnnotationsExtensions.Http);
140ffe3c632Sopenharmony_ci        if (rule != null)
141ffe3c632Sopenharmony_ci        {
142ffe3c632Sopenharmony_ci            Console.WriteLine($"    {method.Name}: {rule}");
143ffe3c632Sopenharmony_ci        }
144ffe3c632Sopenharmony_ci        else
145ffe3c632Sopenharmony_ci        {
146ffe3c632Sopenharmony_ci            Console.WriteLine($"    {method.Name}: no HTTP binding");
147ffe3c632Sopenharmony_ci        }
148ffe3c632Sopenharmony_ci    }
149ffe3c632Sopenharmony_ci}
150ffe3c632Sopenharmony_ci```
151ffe3c632Sopenharmony_ci
152ffe3c632Sopenharmony_ci### Reflection
153ffe3c632Sopenharmony_ci
154ffe3c632Sopenharmony_ciReflection APIs have been extended to enable accessing the new proto2 portions of the library and generated code.
155ffe3c632Sopenharmony_ci
156ffe3c632Sopenharmony_ci * FieldDescriptor.Extension
157ffe3c632Sopenharmony_ci    * Gets the extension identifier behind an extension field, allowing it to be added to an ExtensionRegistry
158ffe3c632Sopenharmony_ci * FieldDescriptor.IsExtension
159ffe3c632Sopenharmony_ci    * Returns whether a field is an extension of another type.
160ffe3c632Sopenharmony_ci * FieldDescriptor.ExtendeeType
161ffe3c632Sopenharmony_ci    * Returns the extended type of an extension field
162ffe3c632Sopenharmony_ci * IFieldAccessor.HasValue
163ffe3c632Sopenharmony_ci    * Returns whether a field's value is set. For proto3 fields, throws an InvalidOperationException.
164ffe3c632Sopenharmony_ci * FileDescriptor.Syntax
165ffe3c632Sopenharmony_ci    * Gets the syntax of a file
166ffe3c632Sopenharmony_ci * FileDescriptor.Extensions
167ffe3c632Sopenharmony_ci    * An immutable list of extensions defined in the file
168ffe3c632Sopenharmony_ci * MessageDescriptor.Extensions
169ffe3c632Sopenharmony_ci    * An immutable list of extensions defined in the message
170ffe3c632Sopenharmony_ci
171ffe3c632Sopenharmony_ci```cs
172ffe3c632Sopenharmony_civar extensions = Baz.Descriptor.Extensions.GetExtensionsInDeclarationOrder(Foo.Descriptor);
173ffe3c632Sopenharmony_civar registry = new ExtensionRegistry();
174ffe3c632Sopenharmony_ciregistry.AddRange(extensions.Select(f => f.Extension));
175ffe3c632Sopenharmony_ci
176ffe3c632Sopenharmony_civar baz = Foo.Descriptor.Parser.WithExtensionRegistry(registry).ParseFrom(input);
177ffe3c632Sopenharmony_ciforeach (var field in extensions)
178ffe3c632Sopenharmony_ci{
179ffe3c632Sopenharmony_ci    if (field.Accessor.HasValue(baz))
180ffe3c632Sopenharmony_ci    {
181ffe3c632Sopenharmony_ci        Console.WriteLine($"{field.Name}: {field.Accessor.GetValue(baz)}");
182ffe3c632Sopenharmony_ci    }
183ffe3c632Sopenharmony_ci}
184ffe3c632Sopenharmony_ci```
185