Home > other >  C# Protobuf Disable Null Checks
C# Protobuf Disable Null Checks

Time:10-13

I have a proto file with this:

message Group {
    string name = 1;
    string id = 2;
}

and the generate code (using Grpc.Tools) gives me code like this for setting name/id:

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Name {
  get { return name_; }
  set {
    name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
  }
}

The thing is, name can be null. If don't set it, I can serialize/deserialize the message fine, but if I try to do group.name=null (usually, I just set it from a db value which may be null) I get an ArgumentNullException - is there a way for the generated code to all nulls? again, nulls are fine, and I can serialize and deserialize the message fine when I just don't set it.

CodePudding user response:

In Protobuf there is no notion of null. Value could be absent in serialized message, then it becomes default in the object. From proto3 documentation:

Default Values

When a message is parsed, if the encoded message does not contain a particular singular element, the corresponding field in the parsed object is set to the default value for that field. These defaults are type-specific:

For strings, the default value is the empty string.

...

Note that for scalar message fields, once a message is parsed there's no way of telling whether a field was explicitly set to the default value (for example whether a boolean was set to false) or just not set at all: you should bear this in mind when defining your message types. ... Also note that if a scalar message field is set to its default, the value will not be serialized on the wire.

So you can assign empty string (default value for strings) to the property.

Also there is optional keyword for the field,

message Group {
    optional string name = 1;

which adds Clear- method to object, and translates to C# code like:

private string name_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Name {
  get { return name_ ?? ""; }
  set {
    name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
  }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool HasName {
  get { return name_ != null; }
}

[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void ClearName() {
  name_ = null;
}

But calling .ClearName() has the same effect on serialized message as assigning it to the default empty string, Name = "". Documentation too states that presence/absence of optional more or less the same:

optional: the same as singular, except that you can check to see if the value was explicitly set.

  • Related