Ver código fonte

Add proto2 doc

Sydney Acksman 6 anos atrás
pai
commit
54a3d8e7ef
1 arquivos alterados com 184 adições e 0 exclusões
  1. 184 0
      docs/csharp/proto2.md

+ 184 - 0
docs/csharp/proto2.md

@@ -0,0 +1,184 @@
+Proto2 support in Google.Protobuf is finally here! This document outlines the new changes brought about 
+by this initial release of proto2 support. The generated code and public API associated with proto2 
+is experimental and subject to change in the future. APIs may be added, removed, or adjusted as feedback is received.
+Generated code may also be modified, adding, removing, or adjusting APIs as feedback is received.
+
+# Generated code
+
+### Messages
+
+Messages in proto2 files are very similar to their proto3 counterparts. However, they have some added properties
+and methods to handle field presence.
+
+A normal single value proto2 fields will have a normal property for getting and setting, as well as a 
+`HasValue` property for checking presence, and a `Clear` method for clearing the value.
+
+```proto
+message Foo {
+    optional Bar bar = 1;
+    required Baz baz = 2;
+}
+```
+```cs
+var foo = new Foo();
+Assert.IsNull(foo.Bar);
+Assert.False(foo.HasBar);
+foo.Bar = new Bar();
+Assert.True(foo.HasBar);
+foo.ClearBar();
+```
+
+### Messages with extension ranges
+
+Messages which define extension ranges implement the `IExtendableMessage` interface as shown below.
+See inline comments for more info.
+
+```cs
+public interface IExtendableMessage<T> : IMessage<T> where T : IExtendableMessage<T>
+{
+    // Gets the value of a single value extension. If the extension isn't present, this returns the default value.
+    TValue GetExtension<TValue>(Extension<T, TValue> extension);
+    // Gets the value of a repeated extension. If the extension hasn't been set, this returns null to prevent unnecessary allocations.
+    RepeatedField<TValue> GetExtension<TValue>(RepeatedExtension<T, TValue> extension);
+    // Gets the value of a repeated extension. This will initialize the value of the repeated field and will never return null.
+    RepeatedField<TValue> GetOrInitializeExtension<TValue>(RepeatedExtension<T, TValue> extension);
+    // Sets the value of the extension
+    void SetExtension<TValue>(Extension<T, TValue> extension, TValue value);
+    // Returns whether the extension is present in the message
+    bool HasExtension<TValue>(Extension<T, TValue> extension);
+    // Clears the value of the extension, removing it from the message
+    void ClearExtension<TValue>(Extension<T, TValue> extension);
+    // Clears the value of the repeated extension, removing it from the message. Calling GetExtension after this will always return null.
+    void ClearExtension<TValue>(RepeatedExtension<T, TValue> extension);
+}
+```
+
+### Extensions
+
+Extensions are generated in static containers like reflection classes and type classes. 
+For example for a file called `foo.proto` containing extensions in the file scope, a 
+`FooExtensions` class is created containing the extensions defined in the file scope.
+For easy access, this class can be used with `using static` to bring all extensions into scope.
+
+```proto
+option csharp_namespace = "FooBar";
+extend Foo {
+    optional Baz foo_ext = 124;
+}
+message Baz {
+    extend Foo {
+        repeated Baz repeated_foo_ext = 125;
+    }
+}
+```
+```cs
+public static partial class FooExtensions {
+    public static readonly Extension<Foo, Baz> FooExt = /* initialization */;
+}
+
+public partial class Baz {
+    public partial static class Extensions {
+        public static readonly RepeatedExtension<Foo, Baz> RepeatedFooExt = /* initialization */;
+    }
+}
+```
+```cs
+using static FooBar.FooExtensions;
+using static FooBar.Baz.Extensions;
+
+var foo = new Foo();
+foo.SetExtension(FooExt, new Baz());
+foo.GetOrInitializeExtension(RepeatedFooExt).Add(new Baz());
+```
+
+# APIs
+
+### Message initialization
+
+Checking message initialization is not handled automatically by the library, but can be done manually via the
+`IsInitialized` extension method in `MessageExtensions`. Please note, 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.
+
+### Extension registries
+
+Just like in Java, extension registries can be constructed to parse extensions when reading new messages
+from input streams. The API is fairly similar to the Java API with some added bonuses with C# syntax sugars.
+
+```proto
+message Baz {
+    extend Foo {
+        optional Baz foo_ext = 124;
+    }
+}
+```
+```cs
+var registry = new ExtensionRegistry() 
+{ 
+    Baz.Extensions.FooExt
+};
+var foo = Foo.Factory.WithExtensionRegistry(registry).ParseFrom(input);
+Assert.True(foo.HasExtension(Bas.Extensions.FooExt));
+var fooNoRegistry = Foo.Factory.ParseFrom(input);
+Assert.False(foo.HasExtension(Bas.Extensions.FooExt));
+```
+
+### Custom options
+
+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 
+repeated fields and messages will be deep cloned.
+
+Example based on custom options usage example [here](https://github.com/protocolbuffers/protobuf/issues/5007#issuecomment-411604515).
+```cs
+foreach (var service in input.Services)
+{
+    Console.WriteLine($"  {service.Name}");
+    foreach (var method in service.Methods)
+    {
+        var rule = method.GetOption(AnnotationsExtensions.Http);
+        if (rule != null)
+        {
+            Console.WriteLine($"    {method.Name}: {rule}");
+        }
+        else
+        {
+            Console.WriteLine($"    {method.Name}: no HTTP binding");
+        }
+    }
+}
+```
+
+### Reflection
+
+Reflection APIs have been included to access the new portions of the library.
+
+ * FieldDescriptor.Extension
+    * Gets the extension identifier behind an extension field, allowing it to be added to an ExtensionRegistry
+ * FieldDescriptor.IsExtension
+    * Returns whether a field is an extension of another type.
+ * FieldDescriptor.ExtendeeType
+    * Returns the extended type of an extension field
+ * IFieldAccessor.HasValue
+    * Returns whether a field's value is set. For proto3 fields, throws an InvalidOperationException.
+ * FileDescriptor.Syntax
+    * Gets the syntax of a file
+ * FileDescriptor.Extensions
+    * An immutable list of extensions defined in the file
+ * MessageDescriptor.Extensions
+    * An immutable list of extensions defined in the message
+
+```cs
+var extensions = Baz.Descriptor.Extensions.GetExtensionsInDeclarationOrder(Foo.Descriptor);
+var registry = new ExtensionRegistry();
+registry.AddRange(extensions.Select(f => f.Extension));
+
+var baz = Foo.Descriptor.Parser.WithExtensionRegistry(registry).ParseFrom(input);
+foreach (var field in extensions)
+{
+    if (field.Accessor.HasValue(baz))
+    {
+        Console.WriteLine($"{field.Name}: {field.Accessor.GetValue(baz)}");
+    }
+}
+```