简体   繁体   中英

Calling F# discriminated union from C# method using UWP, .NET Core v2.0.3 and C# v7.3?

Our app's UWP libraries limit us to using .NET Core 2.0.3. Our code uses C# v7.3 and we have been experimenting with F#.

How does one handle a discriminated union returned from F# in in our versions of .NET Core v2.0.3 and C# v7.3?

Some advice is to use a C# switch to handle an F# function returned discriminated union .

Putting the following F# and C# code in a test Console app with and F# and C# project...

F#

type LogLevels =
| Error
| Warning
| Info

C# calling F#

private static void Main()
{
    LogLevels level = LogLevels.Info;
    switch (level.Tag)
    {
        case LogLevels.Tags.Error:
            Console.WriteLine("error");
            break;
        case LogLevels.Tags.Warning:
            Console.WriteLine("warning");
            break;
        case LogLevels.Tags.Info:
            Console.WriteLine("info"); //prints info
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }
}

….works fine just as @madreflection says.

But if a System.Threading.Tasks.Task is returned instead of an int I get the compiler error CS8370: Feature 'type pattern' is not available in C# 7.3. Please use language version 9.0 or greater. CS8370: Feature 'type pattern' is not available in C# 7.3. Please use language version 9.0 or greater.

In my attempt I retrieve a key from an Azure key vault using an API that works in C# and should in F#.

The F# code is …

type public SENSITIVE_ITEM =
| SECRET_C of KeyVaultSecret
| KEY_C of KeyVaultKey

type public TASK_SENSITIVE_ITEM =
| TASK_GET_SECRET_C of Task<Azure.Response<KeyVaultSecret>>
| TASK_GET_KEY_C of Task<Azure.Response<KeyVaultKey>>

let GetAsync ( item : SENSITIVE_ITEM) (vaultURI : Uri) : TASK_SENSITIVE_ITEM =
    match item with
    | SECRET_C(secret) -> VClient_Secret(vaultURI).GetSecretAsync(secret.Name) |> TASK_GET_SECRET_C
    | KEY_C(key) -> VClient_Key(vaultURI).GetKeyAsync(key.Name) |> TASK_GET_KEY_C

...and the C# code in my unit test for GetAsync is …

public void GetAsync_Key()
{
    KeyVaultKey key = new KeyVaultKey(keyName);

    var fs_sensitive_item_key = KeyVaultAccess.SENSITIVE_ITEM.NewKEY_C(key);

    var task = KeyVaultAccess.GetAsync(fs_sensitive_item_key, vaultUri);
    switch (task)
    {
        case KeyVaultAccess.TASK_SENSITIVE_ITEM.TASK_GET_KEY_C:
            Console.WriteLine("got a key task.");
            break;
        case KeyVaultAccess.TASK_SENSITIVE_ITEM.TASK_GET_SECRET_C:
            Console.WriteLine("got a secret task.");
            break;
        default:
            break;
    }

    Assert.True(false);
}

The two C# case match expressions give the error. This is probably because C# 7.0.3 doesn't support pattern matches in switches. (as the error says).

This is a problem as UWP is not supported in .NET 5.0 which is needed to use C# v9.0 or greater.

So, How does one handle a discriminated union returned from F# in in our limited versions of .NET Core v2.0.3 and C# v7.3?

The F# compiler generates so called "augmentations" for Discriminated Unions.

When using your LogLevel type from C# you can access/check for a certain case using the generated Is[caseName] Properties.

https://sharplab.io/#v2:DYLgZgzgNAJiDUAfALgTwA4FMAEAZA9gOa6YBumwE2AvALABQi2AogE6v6sNMDqAhqwB2AS0GFu2AJKCw+IA

Discriminated Union with case values.

https://sharplab.io/#v2:DYLgZgzgNAJiDUAfA9gBwKYDsAEBlAnhAC7oC2AdACoAWATugIYwCWmA5lQxANYQCwAKEFF8GbAHVaDVBlrYAvNkGJsAQWzIw2Sl24AeAEbJkwAHzLsAIQ1adPPcVqs2poA=

With the advice from madreflection I figured this out...

Use the *.Tags.* nested class members as follows...

switch (task.Tag)
    {
    case KeyVaultAccess.TASK_SENSITIVE_ITEM.Tags.TASK_GET_KEY_C:
        Console.WriteLine("got a key task.");
        break;
    case KeyVaultAccess.TASK_SENSITIVE_ITEM.Tags.TASK_GET_SECRET_C:
        Console.WriteLine("got a secret task.");
        break;
    default:
        Console.WriteLine("default.");
        break;
    }

This works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM