Skip to the content.

在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")!;

上面只是在我的项目里遇到的两个常见问题,以及我的修改方法。仅供参考。

Written on December 14, 2021