如何在.NET中用单表达式初始化Protocol Buffers生成的C#类?
简洁初始化Protobuf生成的带只读RepeatedField的C#类
这个问题我太有共鸣了——protobuf生成的C#类里那些只读的RepeatedField确实会打断我们想用对象初始化器写单表达式的流畅感!不过其实有几个巧妙的办法能让你回到简洁的单表达式初始化,不用拆分成多步。
最推荐:利用C#集合初始化器语法糖
你可能不知道,C#的集合初始化器不仅可以用来创建新集合,还能对已存在的集合调用Add方法——而RepeatedField刚好实现了支持这个语法的接口(它有Add方法,并且实现了IEnumerable)。所以你完全可以这样写:
SearchResponse GetSearchResponse => new SearchResponse { Results = { new Result { Url = "...", Title = "...", Snippets = { "a", "b", "c" } } } };
这里的Results = { ... }和Snippets = { ... }并不是给属性赋值(毕竟没有setter),而是C#帮你自动调用了Results.Add(...)和Snippets.Add(...),完美实现单表达式初始化,和你最开始的理想写法几乎一样!
进阶:用扩展方法实现链式初始化
如果你的初始化逻辑更复杂,或者想让代码可读性更强,可以写个简单的扩展方法来封装AddRange之类的操作:
public static class ProtobufExtensions { public static Result WithSnippets(this Result result, params string[] snippets) { result.Snippets.AddRange(snippets); return result; } }
然后就能用链式调用的方式初始化:
SearchResponse GetSearchResponse => new SearchResponse { Results = { new Result { Url = "...", Title = "..." }.WithSnippets("a", "b", "c") } };
这种方式特别适合需要给集合批量添加元素,或者想把初始化逻辑复用的场景。
批量初始化多个元素的场景
如果要一次性添加多个Result,同样可以用集合初始化器直接搞定:
SearchResponse GetSearchResponse => new SearchResponse { Results = { new Result { Url = "url1", Title = "title1", Snippets = { "s1", "s2" } }, new Result { Url = "url2", Title = "title2", Snippets = { "s3" } } } };
本质还是C#帮你逐个调用Results.Add(),完全不需要手动创建中间集合再AddRange。
内容的提问来源于stack exchange,提问作者Yair Halberstadt
相关产品推荐
相关产品推荐

