Mirai-NET-Shelter / Mirai.Net

Mirai.Net是基于mirai-api-http实现的轻量级mirai社区sdk。
GNU Affero General Public License v3.0
186 stars 26 forks source link

在链式调用中增加.If()方法 #86

Closed Natsukage closed 1 month ago

Natsukage commented 11 months ago

MessageChainBuilder的改善,使得可以通过.If(isAdmin).AtAll()...这样的方式,通过条件判断来决定拼接还是忽略下一个元素。 这可以简化复杂的消息链拼接,尤其是在包含非纯文本的元素时,例如消息可能需要包含多张图片,以及前面提到的At全体等。你也可以.Plain("123").If(true).Clear().Plain("456")这样的方式,在必要的时候直接使用Clear()清除之前的内容。

_ = x.SendMessageAsync(new MessageChainBuilder()
    .Plain($"文字内容是{x.MessageChain.GetPlainMessage()}")
    .If(isVal).Plain("\n内容是数字!恭喜你获得了大奖!")
    .If(isAdmin).AtAll()
    .Build());

在之前,这种可能需要动态添加元素内容的情况只能手动构建MessageChain然后往里面Add元素,无法充分利用MessageChainBuilder的灵活性。在链式调用中添加If()可以极大地改善这种情况,让MessageChainBuilder的适用范围更广。

此改动不会影响原本的MessageChainBuilder的正常工作。

Natsukage commented 11 months ago

关于在ImageMessage中添加Size,ImageType,IsEmoji字段这个commit 参考 MAH的Issue,这三个字段实际上是有效的,只是文档没有更新 但是由于mirai一侧的问题,ImageType属性只能(从mirai端)接收,而不能发送(给mirai端),在直接复读ImageMessage时,其他属性全部可以正常传递,而ImageType会变为Unknown,导致即使IsEmoji正确传递,其他客户端看到的图片依然是放大后的图片,而非表情。 此问题在2.15.0版本的Mirai中存在,但是在2.16.0版本的Mirai中应该已经得到修复。

Mliybs commented 11 months ago

一直在上学没看见orz 不过在链式调用中加入流程控制貌似会让程序变得更难调试 以及有意义不明的情况出现(流程控制程序会控制几条语句?如果我要控制多条语句呢?) 即使消除了也失去了链式调用的灵活性(我加个匿名函数进去,会不会让调用链显得更臃肿了?) 链式调用的使用场景和风格本身让它不适合加入流程控制,要进行控制的话反而if else语句更合适一点,清晰的同时灵活性高 所以我个人不是很推荐这样()

关于添加字段,对于未填充的字段Newtonsoft.Json会默认赋null值,所以对于兼容性不确定的字段添加个可为null好一点()

Natsukage commented 11 months ago

If()只会控制下一个非If()非Build()的语句,多个If()连续并没有意义,只有最后一个会生效。上面给出过例子,例如

.If(isVal).Plain("\n内容是数字!恭喜你获得了大奖!")
.If(isAdmin).AtAll()

的第一个If()不会控制AtAll()

之所以加入控制语句主要是因为MessageChainBuilder的使用场合比较特殊,MessageChain并不容易在中间事后插入内容,这就使得复杂的MessageChain往往需要一次性拼装完毕。

其实主要也就是SendMessageAsync中直接使用MessageChainBuilder构建复杂MessageChain的情况,例如这种 _ = receiver.SendMessageAsync(new MessageChainBuilder().At(receiver.Sender.Id).Plain($"开启了决斗,{(receiver.Sender.MemberProfile.Gender == Genders.Female ? "她" : "他")}渴望一个有价值的对手。").Build());

例如AtAll这种需要判断bot权限决定是否拼装的内容,如果需要拼接在整个消息链中间的话,使用传统的if else只能分别写两条SendMessageAsync,或者是先单独创建一个MessageChainBuilder,然后让其进行.Plain().AtAll()等,最后再Build()发送……虽然这样的用法本身也没什么问题,但是这种操作完全可以通过直接操作MessageChain来实现,MessageChainBuilder在这里就没什么实际意义了。往往最需要MessageChainBuilder的就是上面举例的这种,直接在SendMessageAsync()里面现搓一个MessageChain出来的情况。

尤其是一些特殊的需求中,例如说,以图搜番,搜图插件,在拼接输出模板时可能有大量要素,例如at发送者,如果是OVA则不拼接“第几集”的信息和图标,如果不是R18番剧才能拼接图片,否则跳过图片……这样的复杂模板本来可以通过MessageChainBuilder一次性解决,通过传统的 If else则会徒增复杂度,也让Builder的实用性大大降低。

而且If()的使用与否是可选项,并不会影响Builder原本的用法,原先使用Builder的地方也不需要修改代码。

当然确实这个功能不是必须的,只是因为我个人认为会方便一些。如果出于规范考虑不merge也是没问题的。

Natsukage commented 11 months ago

关于nullable的问题,c#中的string类型本来就是可以为null的…

Mliybs commented 11 months ago

引用类型都能为null 但是在不表明null的情况下IDE不会提示的

Natsukage commented 11 months ago

引用类型都能为null 但是在不表明null的情况下IDE不会提示的

如果单纯是考虑ide提示的话就更没必要了吧,之前的issue中已经列举过,当前mah版本中,isemoji属性本身就是常规属性,和height等地位相同。既然其他属性都没有特别标注为nullable,单独对这三个属性进行标注反而是没道理的。 从commit记录来看,这个属性实际上已经被支持很久了,只是文档没有更新而已。并且现在旧版本的mirai由于各种原因实际上早就退环境无法使用了,并没有必要特别考虑对旧版本的兼容性。