Function with return type of 'string' returns a nullable string (ie 'string?')

与世无争的帅哥 提交于 2021-01-28 05:20:31

问题


For an Azure Functions project I am using C# 8 with enabled nullable reference types. Since with AzureFunctions AppSettings are exposed via environment variables, which can be a string or null (i.e. they return string?) I tried to encapsulate the logic of getting environment variables - and throwing an error if they're not set - into a separate method GetEnvVariable.

As you can see, GetEnvVariable is implemented in three short lines. If the environment variable is not set (i.e it is null) it throws a custom exception, else the string value is returned.

The following line does not show a problem of "possible de-reference of null" because the compiler know, that at this line env must be string (not string?) because the exception would have fired already and this line could not have been reached.

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

Still, when hovering over the variable env with the mouse the type is displayed as string?

Does this make sense? If so, why? env is assigned the output of the GetEnvVariable method, which return string.

Does throwing an exception implicitly return null? Please help me understand, your input is really appreciated. Cheers!

Here's my code


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.") {}
        }
    }
}

Also here's my full *.csproj showing that nullable reference types are enabled globally.

<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>

回答1:


Throwing an exception does not make your method return null or any other value.

When you declare a var of a reference type, the compiler will always infer a nullable type for it. The reason for this is that the compiler has full knowledge of whether or not the variable could contain null at any point in the method--so if you wanted to do something like the following, the compiler can understand what you're doing and stay out of your way:

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 will show you the null state the compiler has inferred for your variable in Quick Info (by hovering over the variable):

See also the notes from the C# design team on the decision to make var always infer a nullable reference type.


Below is some more context on what the language is doing:

Nullability analysis tracks both the declared type of a variable and the flow state of a variable. Consider an example like the following:

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());

In the above example, s is of type string?, but the compiler knows at each point whether or not it could contain null-- so it's OK to access members on it or pass it off to methods that require a string argument.




回答2:


the compiler know, that at this line env must be string (not string?) because the exception would have fired already and this line could not have been reached.

No, it doesn't. The compiler does not do in-depth analysis to know that your function cannot return a null value.

If you've enabled nullable reference support either within the .csproj file or via a #nullable enable directive, then using the string return type (as opposed to string?) for GetEnvVariable informs the compiler that the reference cannot be set be null. Without that support turned on, the compiler assumes that the string van be null.



来源:https://stackoverflow.com/questions/61898776/function-with-return-type-of-string-returns-a-nullable-string-ie-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!