返回类型为“字符串”的函数将返回可为空的字符串(即“字符串?”)

时间:2020-05-19 19:02:54

标签: c# .net-core azure-functions nullable-reference-types

对于Azure Functions项目,我使用具有启用的可空引用类型的C#8。由于使用AzureFunctions,AppSettings通过环境变量公开,环境变量可以是字符串或null(即,它们返回string?),因此我试图封装获取环境变量的逻辑-如果未设置则抛出错误。单独的方法GetEnvVariable

如您所见,GetEnvVariable由三行简短的代码实现。如果未设置环境变量(即null),则会抛出自定义异常,否则将字符串值返回

以下行未显示“可能取消引用null”的问题,因为编译器知道,在此行env必须为string(而不是string?),因为该异常将已经触发,而无法到达此行。

var length = env.Contains('$');

仍然,当用鼠标悬停在变量env上时,类型显示为string?

这有意义吗?如果是这样,为什么?为env分配了GetEnvVariable方法的输出,该方法返回string

引发异常是否隐式返回null?请帮助我理解,非常感谢您的投入。干杯!

这是我的代码


namespace delme_azf
{
    public static class kv
    {
        [FunctionName("kv")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            try
            {
                var envName = "lolomat";
                var env = GetEnvVariable(envName);
                var length = env.Contains('$');
                return new OkObjectResult($"success {env}");
            }
            catch (System.Exception)
            {
                throw;
            }
        }


        public static string GetEnvVariable(string name)
        {
            var env = Environment.GetEnvironmentVariable(name);
            if (env == null) throw new EnvironmentVariableNotSetException(nameof(name));
            return env;
        }


        public class EnvironmentVariableNotSetException : Exception
        {
            public EnvironmentVariableNotSetException() {}
            public EnvironmentVariableNotSetException(string envName) : base($"Mandatory environment variable '{envName}' is not set.") {}
        }
    }
}

enter image description here

这也是我完整的* .csproj,显示了可空引用类型已全局启用。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
    <RootNamespace>delme_azf</RootNamespace>
  </PropertyGroup>
  <PropertyGroup>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
    <PackageReference Include="Oracle.ManagedDataAccess.Core" Version="2.19.70" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

2 个答案:

答案 0 :(得分:1)

引发异常不会使您的方法返回null或任何其他值。

当您声明引用类型的var时,编译器将始终为其推断可为null的类型。这样做的原因是,编译器完全了解该变量在方法中的任何位置是否可以包含null,因此,如果您想执行以下操作,则编译器可以了解您在做什么并留下来挡路:

var x = "initial value";
Console.WriteLine(x.ToString()); // ok

if (someCondition)
{
    // there's no warning on this assignment, because
    // `var x` was inferred to have a `string?` type in the beginning.
    x = null;
}

CarryOnWith(x); // ok, assuming the method accepts a possibly null string

Visual Studio将向您显示编译器为快速信息中的变量推断出的空状态(将鼠标悬停在变量上):

Quick Info example 1

Quick Info example 2

另请参阅C#设计团队的notes关于使var始终推断可为空的引用类型的决定。


下面是有关该语言在做什么的更多上下文:

可空性分析同时跟踪变量的声明类型和变量的流状态。考虑如下示例:

string? s = null;
if (s != null)
{
    // if we somehow got here, s was not null.
    Console.WriteLine(s.ToString());
}
else
{
    // warning: dereference of a possibly null reference
    Console.WriteLine(s.ToString());
}

s = "hello";
// since we know a not-null was assigned, we now know this is safe.
Console.WriteLine(s.ToString());

// additionally the flow state becomes not-null if
// a null value would have definitely caused an exception earlier on:
s = null;
// warning
Console.WriteLine(s.ToString());
// no warning, because the previous line would have already thrown an exception
Console.WriteLine(s.ToString());

在上面的示例中,s的类型为string?,但是编译器在每个点都知道它是否可以包含null,因此可以访问其上的成员或将其传递给需要string参数的方法。

答案 1 :(得分:0)

编译器知道,env这行必须为string(而不是string?),因为该异常已经触发并且无法到达此行。

不,不是。编译器不会进行深入分析来知道您的函数不能返回一个null值。

如果您在.csproj文件中或通过#nullable enable指令启用了可为空的引用支持,则使用string返回类型(而不是string?GetEnvVariable的值会通知编译器该引用不能设置为null。如果没有启用该支持,则编译器会假定字符串van为空。