protobuf-net - сгенерированный класс из.proto - Предполагается, что повторяющееся поле должно быть только для чтения без установщика?

Я полностью запутался в этом. Я оглянулся и не могу найти прямой ответ. У меня есть файл.proto, который мой проект, который все был Java, использует для создания некоторых сообщений.

Есть повторяющееся информационное поле. Какой тип мы создали. Когда я генерирую классы C# с помощью protogen, это поле появляется только для чтения и не имеет установщика.

Я не могу полностью создать сообщение без этого параметра. Итак, мой вопрос. Предполагается, что повторяющиеся поля должны быть сгенерированы таким образом, и я должен получить доступ к этому списку только для чтения другим способом? Или это ошибка в генераторе?

Сгенерированный код:

private readonly global::System.Collections.Generic.List<StringMapEntry> _factoryProperty = new global::System.Collections.Generic.List<StringMapEntry>();
[global::ProtoBuf.ProtoMember(2, Name=@"factoryProperty", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<StringMapEntry> factoryProperty
{
  get { return _factoryProperty; }
}

Раздел Прото файла:

repeated StringMapEntry factoryProperty = 2;

Я, наверное, просто упустил что-то действительно очевидное. Спасибо за любую помощь!

2 ответа

Решение

Список не только для чтения... Вы просто изменяете список, который он вам дает:

var order = new Order();
order.Lines.Add( new OrderLine {...} );

На самом деле для под-коллекций довольно распространено быть только для получения. Это не значит, что вы не можете изменить содержимое.

Это была новая проблема для нас после обновления нашего исполняемого файла proto-net и связанных с ним файлов. Это было новое поведение, которого мы не испытывали раньше.

Немного покопавшись в csharp.xslt, мы нашли определение для "повторяющихся" полей:

<xsl:template match="FieldDescriptorProto[label='LABEL_REPEATED']">
    <xsl:variable name="type"><xsl:apply-templates select="." mode="type"/></xsl:variable>
    <xsl:variable name="format"><xsl:apply-templates select="." mode="format"/></xsl:variable>
    <xsl:variable name="field"><xsl:apply-templates select="." mode="field"/></xsl:variable>
    private <xsl:if test="not($optionXml)">readonly</xsl:if> global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:value-of select="$field"/> = new global::System.Collections.Generic.List&lt;<xsl:value-of select="$type"/>&gt;();
    [<xsl:apply-templates select="." mode="checkDeprecated"/>global::ProtoBuf.ProtoMember(<xsl:value-of select="number"/>, Name=@"<xsl:value-of select="name"/>", DataFormat = global::ProtoBuf.DataFormat.<xsl:value-of select="$format"/><xsl:if test="options/packed='true'">, Options = global::ProtoBuf.MemberSerializationOptions.Packed</xsl:if>)]<!--
    --><xsl:if test="$optionDataContract">
    [global::System.Runtime.Serialization.DataMember(Name=@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>, IsRequired = false)]
    </xsl:if><xsl:if test="$optionXml">
    [global::System.Xml.Serialization.XmlElement(@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>)]
    </xsl:if>
    public global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:call-template name="pascal"/>
    {
      get { return <xsl:value-of select="$field"/>; }<!--
      --><xsl:if test="$optionXml">
      set { <xsl:value-of select="$field"/> = value; }</xsl:if>
    }
  </xsl:template>

Я вытащил определенные части для частного поля и сеттера:

private <xsl:if test="not($optionXml)">readonly</xsl:if> ...snip...

public ...snip...
{
  ...snip... 
  <!----><xsl:if test="$optionXml">
  set { <xsl:value-of select="$field"/> = value; }
  </xsl:if>
}

Обратите внимание на подозрительные условия выше для $optionXml. Если вы просто удалите их, поле больше не будет доступно только для чтения, и установщик будет создан правильно.

Так что тогда становится: частный... отрываться...

public ...snip...
{
  ...snip... 
  set { <xsl:value-of select="$field"/> = value; }
}

Полный "исправленный" шаблон:

  <xsl:template match="FieldDescriptorProto[label='LABEL_REPEATED']">
    <xsl:variable name="type"><xsl:apply-templates select="." mode="type"/></xsl:variable>
    <xsl:variable name="format"><xsl:apply-templates select="." mode="format"/></xsl:variable>
    <xsl:variable name="field"><xsl:apply-templates select="." mode="field"/></xsl:variable>
    private global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:value-of select="$field"/> = new global::System.Collections.Generic.List&lt;<xsl:value-of select="$type"/>&gt;();
    [<xsl:apply-templates select="." mode="checkDeprecated"/>global::ProtoBuf.ProtoMember(<xsl:value-of select="number"/>, Name=@"<xsl:value-of select="name"/>", DataFormat = global::ProtoBuf.DataFormat.<xsl:value-of select="$format"/><xsl:if test="options/packed='true'">, Options = global::ProtoBuf.MemberSerializationOptions.Packed</xsl:if>)]<!--
    --><xsl:if test="$optionDataContract">
    [global::System.Runtime.Serialization.DataMember(Name=@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>, IsRequired = false)]
    </xsl:if><xsl:if test="$optionXml">
    [global::System.Xml.Serialization.XmlElement(@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>)]
    </xsl:if>
    public global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:call-template name="pascal"/>
    {
      get { return <xsl:value-of select="$field"/>; }
      set { <xsl:value-of select="$field"/> = value; }
    }
  </xsl:template>

Я поиграл с параметром optionXml в false, но он не работал, и вы все равно можете захотеть включить эту опцию в любом случае.

Другие вопросы по тегам