用于空 F# 可区分联合案例的 C# 类型
C# types for empty F# discriminated union cases
我正在使用 C# 访问 F# 可区分联合,并尝试在联合的案例上使用 switch 语句。这适用于至少具有一个字段但不适用于空值的值,因为这些值没有生成相应的 class,只有 属性。考虑以下 F# 可区分联合。
type Letter = A of value:int | B of value:string | C | D
在 C# 中,我在函数中有以下 switch 语句,该函数的参数字母类型为 Letter:
switch (letter)
{
case A a: Console.WriteLine(a.value); break;
case B b: Console.WriteLine(b.value); break;
default:
if (letter.IsC) Console.WriteLine("C");
else if (letter.IsD) Console.WriteLine("D");
}
默认情况处理联合值为空的情况。我更喜欢:
switch (letter)
{
case A a: Console.WriteLine(a.value); break;
case B b: Console.WriteLine(b.value); break;
case C c: Console.WriteLine("C"); break;
case D d: Console.WriteLine("D"); break;
}
但这不起作用,因为类型名称 C 和 D 不存在 - C 和 D 是属性而不是类型。我可以通过给 C 和 D 一个单位类型的字段来规避这个问题,但这不是很优雅。为什么只为非空的可区分联合值创建类型,最好的解决方法是什么?
我不认为猜测为什么 F# DU 是按照语言规范部分 8.5.4 Compiled Form of Union Types for Use from Other CLI Languages 规定的方式实现的从 C# 使用 F# DU 时很重要。
此类互操作场景的良好设计是避免使用 "raw" DU,而是将此实现细节隐藏在 F# 会向其他 CLI 语言公开的某些接口后面。
在少数情况下(例如 this one and that one)SO 涵盖了从 C# 使用 F# DU 的问题,并给出了如何使用的建议正确的方法.
但是,如果您坚持 错误的方式 并且您的 C# 依赖于 F# DU 实现的细节,那么以下 C# hack 就可以:
namespace ConsoleApp1
{
class Program {
private static void unwindDU(Letter l)
{
switch (l.Tag)
{
case Letter.Tags.A: Console.WriteLine(((Letter.A)l).value); break;
case Letter.Tags.B: Console.WriteLine(((Letter.B)l).value); break;
case Letter.Tags.C: Console.WriteLine("C"); break;
case Letter.Tags.D: Console.WriteLine("D"); break;
}
}
static void Main(string[] args)
{
unwindDU(Letter.NewA(1));
unwindDU(Letter.C);
}
}
}
执行后会return
1
C
switch (letter)
{
case A a: Console.WriteLine(a.value); break;
case B b: Console.WriteLine(b.value); break;
case Letter l when l == C: Console.WriteLine("C"); break;
case Letter l when l == D: Console.WriteLine("D"); break;
}
空可区分联合使用单例模式,标签通过构造函数传递,因此 属性 C 分配给 new Letter(0),D 分配给 new Letter(1),其中 Letter 是相应的 C# class。 case 语句的第一部分将始终评估为 true,因为 letter 是 Letter 类型。 when 子句指定字母必须等于 Letter 的单例实例,它对应于 C 和 D 的空可区分联合值。
如果您不介意为您的类型增加一点复杂性,您可以像这样定义您的 F# 类型:
type Letter = A of value:int | B of value:string | C of unit | D of unit
完成后,您可以在 C# 中进行模式匹配,如下所示:
switch (letter)
{
case A a: Console.WriteLine("A"); break;
case B b: Console.WriteLine("B"); break;
case C _: Console.WriteLine("C"); break;
case D _: Console.WriteLine("D"); break;
}
我正在使用 C# 访问 F# 可区分联合,并尝试在联合的案例上使用 switch 语句。这适用于至少具有一个字段但不适用于空值的值,因为这些值没有生成相应的 class,只有 属性。考虑以下 F# 可区分联合。
type Letter = A of value:int | B of value:string | C | D
在 C# 中,我在函数中有以下 switch 语句,该函数的参数字母类型为 Letter:
switch (letter)
{
case A a: Console.WriteLine(a.value); break;
case B b: Console.WriteLine(b.value); break;
default:
if (letter.IsC) Console.WriteLine("C");
else if (letter.IsD) Console.WriteLine("D");
}
默认情况处理联合值为空的情况。我更喜欢:
switch (letter)
{
case A a: Console.WriteLine(a.value); break;
case B b: Console.WriteLine(b.value); break;
case C c: Console.WriteLine("C"); break;
case D d: Console.WriteLine("D"); break;
}
但这不起作用,因为类型名称 C 和 D 不存在 - C 和 D 是属性而不是类型。我可以通过给 C 和 D 一个单位类型的字段来规避这个问题,但这不是很优雅。为什么只为非空的可区分联合值创建类型,最好的解决方法是什么?
我不认为猜测为什么 F# DU 是按照语言规范部分 8.5.4 Compiled Form of Union Types for Use from Other CLI Languages 规定的方式实现的从 C# 使用 F# DU 时很重要。
此类互操作场景的良好设计是避免使用 "raw" DU,而是将此实现细节隐藏在 F# 会向其他 CLI 语言公开的某些接口后面。
在少数情况下(例如 this one and that one)SO 涵盖了从 C# 使用 F# DU 的问题,并给出了如何使用的建议正确的方法.
但是,如果您坚持 错误的方式 并且您的 C# 依赖于 F# DU 实现的细节,那么以下 C# hack 就可以:
namespace ConsoleApp1
{
class Program {
private static void unwindDU(Letter l)
{
switch (l.Tag)
{
case Letter.Tags.A: Console.WriteLine(((Letter.A)l).value); break;
case Letter.Tags.B: Console.WriteLine(((Letter.B)l).value); break;
case Letter.Tags.C: Console.WriteLine("C"); break;
case Letter.Tags.D: Console.WriteLine("D"); break;
}
}
static void Main(string[] args)
{
unwindDU(Letter.NewA(1));
unwindDU(Letter.C);
}
}
}
执行后会return
1
C
switch (letter)
{
case A a: Console.WriteLine(a.value); break;
case B b: Console.WriteLine(b.value); break;
case Letter l when l == C: Console.WriteLine("C"); break;
case Letter l when l == D: Console.WriteLine("D"); break;
}
空可区分联合使用单例模式,标签通过构造函数传递,因此 属性 C 分配给 new Letter(0),D 分配给 new Letter(1),其中 Letter 是相应的 C# class。 case 语句的第一部分将始终评估为 true,因为 letter 是 Letter 类型。 when 子句指定字母必须等于 Letter 的单例实例,它对应于 C 和 D 的空可区分联合值。
如果您不介意为您的类型增加一点复杂性,您可以像这样定义您的 F# 类型:
type Letter = A of value:int | B of value:string | C of unit | D of unit
完成后,您可以在 C# 中进行模式匹配,如下所示:
switch (letter)
{
case A a: Console.WriteLine("A"); break;
case B b: Console.WriteLine("B"); break;
case C _: Console.WriteLine("C"); break;
case D _: Console.WriteLine("D"); break;
}