对于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.") {}
}
}
}
这也是我完整的* .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>
答案 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将向您显示编译器为快速信息中的变量推断出的空状态(将鼠标悬停在变量上):
另请参阅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为空。