簡體   English   中英

從 C# 讀取一個 protobuf3 自定義選項

[英]Reading a protobuf3 custom option from C#

長話短說

根據文檔,如果我正在執行 C++,我可以使用string value = MyMessage::descriptor()->options().GetExtension(my_option);讀取自定義選項的值。 . Java 和 Python 有類似的例子。但我正在做 C#,我可以找到一個等價物。 我可以做嗎?如果可以,怎么做?

更多細節

我正在處理使用protobuf3生成的類。 模式正在聲明一個自定義選項 它看起來像這樣:

import "google/protobuf/descriptor.proto";

extend google.protobuf.MessageOptions {
  string my_option = 51234;
}

message MyMessage {
  option (my_option) = "Hello world!";
}

我的代碼被提供了一個從MyMessage生成的 object,我想閱讀這個選項的值(這里是Hello world!


更新:我沒有使用 protobuf.net。 現在 C# 已經被 protobuf 原生支持了,我正在使用谷歌的 protobuf3 C# 庫。

您現在可以在 C# 中訪問自定義選項。 首先,在你的 .proto 中定義自定義選項:

import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
  string objectReferenceType = 1000; //Custom options are 1000 and up.
}

接下來,將自定義選項應用於某些內容。 在這里,我將其附加到一個字段:

message Item
{
  string name = 1;
  int32 id = 2;
  string email = 3;
  ObjectReference prefab = 4 [(objectReferenceType) = "UnityEngine.GameObject"];
}

然后您需要查找自定義選項字段編號。 沒有好的方法可以做到這一點,因此只需從您定義自定義選項擴展名的文件的 FileDescriptor 中查找擴展名。 您將擁有一個 C# 生成的類,稱為 protoFileNameReflection。 從中,您可以找到擴展名,然后是字段編號。 這是一個假設 proto 名為“Item.proto”的示例,因此生成的類稱為 ItemReflection:

foreach (FieldDescriptor extensionFieldDescriptor in ItemReflection.Descriptor.Extensions.UnorderedExtensions)
    {   
        if (extensionFieldDescriptor.ExtendeeType.FullName == "google.protobuf.FieldOptions")
        {
            objectReferenceTypeFieldNumber = extensionFieldDescriptor.FieldNumber;
            break;
        }
    }

然后使用 protobuf 反射訪問代碼中的自定義選項:

FieldDescriptor fieldDescriptor = prefabFieldDescriptor;
CustomOptions customOptions = fieldDescriptor.CustomOptions;
if (customOptions.TryGetString(objectReferenceTypeFieldNumber, out string objectReferenceTypeText))
{
   Console.Log(objectReferenceTypeText); //logs: "UnityEngine.GameObject"
}

看起來這個功能還沒有實現: https : //github.com/google/protobuf/issues/1603

看起來這只是時間問題,他們對拉取請求持開放態度。 因此,根據您需要它的時間,您可能是執行此操作的人:)

更新 Protobuf 3.11.4 的答案,因為這是處理該問題的唯一線程。 使用與 DoomGoober 類似的原型:

// Foo.proto
Package foo
import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
  string objectReferenceType = 1000; //Custom options are 1000 and up.
}
// Bar.proto
import "Foo.proto"
message Item
{
  string name = 1;
  int32 id = 2;
  string email = 3;
  ObjectReference prefab = 4 [(foo.objectReferenceType) = "UnityEngine.GameObject"];
}

您可以使用新生成的類從 Item Proto 對象讀取自定義選項。 在這種情況下,它稱為FooExtensions (參見 Foo.protos):

public void LogFieldOptions(Item item)
{
  // Get the list of fields in the message (name, id, etc...)
  var fieldDescriptors = item.Descriptor.Fields.InFieldNumberOrder();

  foreach (var fieldDescriptor in fieldDescriptors)
  {
    // Fetch value of this item instance for current field
    var fieldValue = fieldDescriptor.Accessor.GetValue(item);

    // Fetch name of field
    var fieldName = fieldDescriptor.Name;

    // if we are not in the correct field: Skip    
    if(!fieldName.Equals("prefab")) continue;

    // Fetch the option set in this field in the proto
    // (note that this is not related to the instance 
    // of item but to the general item message descriptor)
    var optionObjectReferenceType = fieldDescriptor.GetOption(FooExtensions.objectReferenceType); 
    Console.Log(optionObjectReferenceType ); //logs: "UnityEngine.GameObject";
  }
}

您可以以相同的方式獲取所有類型的選項(MessageOptions、FileOptions)。 只需確保您使用正確的描述符(對於 MessageOptions 使用 MessageDescriptors 等...)

閱讀自定義消息選項(擴展)

  • 假設文件名為foobar.proto

message.Descriptor.GetOptions().GetExtension(FoobarExtensions.MyOption);

訪問描述符數據的簡單版本:

public void LogFieldOptions(Item item)
{
   var fieldDescriptors = item.Descriptor.Fields.InDeclarationOrder(); // or .InFieldNumberOrder()
   var fieldDescriptor = fieldDescriptors.FirstOrDefault(fd => fd.Name == "prefab")

   if (fieldDescriptor != null)
   {
       var objectReferenceType = fieldDescriptor.GetOptions().GetExtension(FooExtensions.objectReferenceType); 
       // use result
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM