空F#区分工会案例的C#类型
我正在使用C访问一个F#歧视工会,并试图在工会的案例中使用switch语句。这适用于至少有一个字段的值,但不适用于空值,因为这些值没有生成相应的类,只有一个属性。考虑下面的F判别判别式,空F#区分工会案例的C#类型,c#,f#,switch-statement,discriminated-union,C#,F#,Switch Statement,Discriminated Union,我正在使用C访问一个F#歧视工会,并试图在工会的案例中使用switch语句。这适用于至少有一个字段的值,但不适用于空值,因为这些值没有生成相应的类,只有一个属性。考虑下面的F判别判别式, type Letter = A of value:int | B of value:string | C | D 在C#中,我在一个函数中有以下switch语句,该函数的参数字母类型为字母: switch (letter) { case A a: Console.WriteLine(a.value);
type Letter = A of value:int | B of value:string | C | D
在C#中,我在一个函数中有以下switch语句,该函数的参数字母类型为字母:
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");
}
默认情况处理union值为空的情况。我更喜欢:
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一个类型为unit的字段来避免这个问题,但它不是很优雅。为什么只为非空的有区别的联合值创建类型?最好的解决方法是什么?我不认为,在使用C语言中的F#DUs时,猜测为什么F#DUs是按照语言规范第8.5.4部分中规定的联合类型编译形式实现的,这一点是非常重要的 这种互操作场景的一个好设计是避免使用“原始”DU,而是将此实现细节隐藏在F#将向其他CLI语言公开的某些接口后面 在少数情况下(例如和),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);
}
}
}
在执行过程中,它将返回
1
C
空的判别联合使用单例模式,标记通过构造函数传递,因此属性C被分配给新字母(0),属性D被分配给新字母(1),其中字母是对应的C#类。case语句的第一部分将始终计算为true,因为letter是letter类型。when子句指定字母必须等于字母的单例实例,该实例对应于空的区分并集值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;
}
您是否尝试过将F#编译成程序集,然后反编译成C#?谢谢您的建议。我看了一下F#反编译成C#here(),这导致了我下面给出的答案。问题中提到了这种可能性。我在这里写了几个选项:如果这个问题中出现了新的选项,我将添加更多选项。
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;
}