2

I've done some research, but have not found an answer to this. Is there a to represent the null case in the c# 8 switch expressions in such a way that the compiler will recognize and not trigger a warning for the reference x in the base case when calling ToString()? It seems like this is an obvious case and that I should not need to use the null forgiving operator ! in this case.

public override int? ConvertToInt(object? value) => value switch
{
    var x when x == null => null,
    int x => x,
    var x => int.Parse(x!.ToString())
};

I have a feeling that they just haven't got to this yet, but I figured I'd toss the question out there.

Edit:

I did come up with a way to eliminate the need for the null forgiving operator, but I'm still curious as to if there's a specific null case syntax that is recognized. This doesn't feel like the best way as it's not completely clear, and I'm not even sure if this will be honored as I don't think Nullable references actually affect anything at run time, I will test this shortly.

public override int? ConvertToInt(object? value) => value switch
{    
    int x => x,
    // notice the non-nullable object
    object x => int.Parse(x.ToString()),
    _ => null
};

Edit 2:

It looks like I was mistaken, this does seem to be honored. When running the following test the assertion did not fail.

[TestMethod]

public void MyTestMethod()
{
    object? could_be_null = null;
    string? str = could_be_null switch
    {
        object x => x.ToString(),
        _ => null
    };

    Assert.IsNull(str);
}
Jesse
  • 915
  • 1
  • 11
  • 20

2 Answers2

1

After a bit of experimentation as displayed in the edits of the original question I came up with this solution. To my surprise the nullability of reference typed is checked at run time. This is the best that I could come up with, if someone can come up with something better, or there is an official syntax for the null case that I'm unaware of, I'll gladly accept your answer over mine.

public override int? ConvertToInt(object? value) => value switch
{    
    int x => x,
    // notice the non-nullable object
    object x => int.Parse(x.ToString()),
    _ => null
};
Jesse
  • 915
  • 1
  • 11
  • 20
  • 1
    A bit more verbose than a ternary operator but it's interesting to note how versatile the new switch expression is and how nullable-reference types have been integrated into C#. I just hope they continue working on strong typing C# around nullable types and making it more functional. – Paul-Sebastian Manole Apr 23 '22 at 16:07
  • @Paul-SebastianManole There's three cases here. I think the verbosity is about equal to three cases using ternary operator. Add the fourth case in and it starts becoming less verbose, also switch expressions allow for pattern matching which I don't believe is allowed using the ternary operator. I don't think that it eliminates the needs for ternary operator, because it is more verbose in simple cases, but it is a nice extra tool to have. – Jesse Apr 25 '22 at 20:21
1

I also pondered about this some time ago. Specifically, around whether to use a ternary operator or the new switch expression which respects and checks the nullability of reference types at runtime.

Example, which do you prefer, switch expression:

private void SetProductCategoryHierarchyFromParentNode() => ProductCategoryHierarchy =
        ParentNode switch {
            ProductCategoryHierarchyNode node => node.ProductCategoryHierarchy,
            _ => ProductCategoryHierarchy.Default,
        };
};

or ternary operator:

private void SetProductCategoryHierarchyFromParentNode() => ProductCategoryHierarchy =
        ParentNode is not null
        ? ParentNode.ProductCategoryHierarchy
        : ProductCategoryHierarchy.Default;

I would go for any of them, but one thing to note is that with the switch expression, one could easily introduce structural validation by pattern matching at a later time. For example:

private void SetProductCategoryHierarchyFromParentNode() => ProductCategoryHierarchy =
        ParentNode switch {
            { HierarchyLevel: > 10 } => throw new Exception("Product category hierarchies deeper than 10 levels are strictly prohibited."),
            ProductCategoryHierarchyNode node => node.ProductCategoryHierarchy,
            _ => ProductCategoryHierarchy.Default,
        };
Paul-Sebastian Manole
  • 2,538
  • 1
  • 32
  • 33
  • I think in this case either would be perfectly fine. I think that both are nice tools for the belt honestly, and I still actively use both probably depending both on mood and situation. – Jesse Apr 25 '22 at 20:24