在Teams app代码中enable nullable
昨天讲了一下如何把代码升级到 net6,今天我优化了好几个小时更新代码,enable了nullable。
c#的nullable我一直非常喜欢,它可以帮助开发人员,让开发人员去思考,哪些地方需要可以为null,哪些地方不需要。它并不是万能的灵丹妙药,但是它的确可以大大的提高代码质量。我自己通过在LuckyDraw里enable了nullable,从而发现了好几个潜在的bug。现在一些其他语言,比如typescript也有类似功能,所以我觉得这个会是以后开发语言的一种趋势。
这篇文章我来分享一下我遇到的一些nullable的问题,和如何解决的,希望对大家有一点点帮助。
首先,我们需要在csproj文件中加上 <Nullable>enable</Nullable>
来让编译器知道我们希望打开nullable开关。
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>10</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
...
保存csproj文件后,稍等几秒钟后,你就会发现你的代码里多了很多警告,这就是 c# 编译器发现的一些可能是潜在的问题。
首先是和json相关的,比如:
var editForm = JsonSerializer.Deserialize<CompetitionEditForm>(str);
editForm.abc ...;
这里的warning在第二行,原因是 JsonSerializer.Deserialize<T>()
的返回值可能为 null,所以我们不能直接就开始使用 editForm
,我们需要做一个判断:
var editForm = JsonSerializer.Deserialize<CompetitionEditForm>(str);
if (editForm != null)
{
editForm.abc ...;
}
当然这种改发稍微有点麻烦,每个地方都需要加上 if 判断。我的做发是增加一个新的 method,如下:
public static class JsonHelper
{
public static TValue Deserialize<TValue>(string json, JsonSerializerOptions? options = null)
{
var value = JsonSerializer.Deserialize<TValue>(json, options);
if (value == null)
{
throw new Exception($"A non-null value is expected, but the result of Deserialize<{typeof(TValue).FullName}>() is null.");
}
return value;
}
}
这样我们确保我们这个方法不会返回 null,所以之前的代码就可以改成下面这样,没有warning。
var editForm = JsonHelper.Deserialize<CompetitionEditForm>(str);
editForm.abc ...;
另外还有一块也是和json相关的,因为目前teams bot sdk还是使用Newtonsoft.JSON,所以我们的teams app里还是有很大一部分代码还是会和 Newtonsoft.JSON 发生关系。比如:
public static string GetBotMessagePreviewAction(this Activity activity)
{
var value = (JObject)activity.Value;
var botMessagePreviewAction = (string)value.GetValue("botMessagePreviewAction");
return botMessagePreviewAction;
}
因为 activity 的 Value 是 JObject,而 JObject 的 GetValue() 可能会返回空,所以上面的代码需要对 botMessagePreviewAction 进行是否为 null 的判断。不过因为我在其他地方做过判断,只要调用这个方法,就说明 JObject 里肯定有 botMessagePreviewAction
这个属性。所以我采用了一个简单的改法,使用 !
,在语句最后加了 !
,来告诉编译器,我确定不会为 null。
var botMessagePreviewAction = (string)value.GetValue("botMessagePreviewAction")!;
上面只是在我的项目里遇到的两个常见问题,以及我的修改方法。仅供参考。