Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 模式匹配C代码中的F#类型_C#_F#_Interop - Fatal编程技术网

C# 模式匹配C代码中的F#类型

C# 模式匹配C代码中的F#类型,c#,f#,interop,C#,F#,Interop,假设有一个F#定义: type one=| a的左边| b的右边 设f(i:int):或者= 如果i>0 然后我离开了 否则“什么都没有” 函数f用于C代码: var a=Library.f(5); 如何为数据构造函数匹配结果值a?比如: /* (如果a是左x) 用x做点什么 (如果a正确,则为y) 和我做点什么 */ 使用F#区别于C#的联合有点不雅观,因为它们是如何编译的 我认为最好的方法是定义一些成员(在F#端),以简化使用C#中的类型。有多种选择,但我更喜欢的是定义TryLeft和T

假设有一个
F#
定义:

type one=| a的左边| b的右边
设f(i:int):或者=
如果i>0
然后我离开了
否则“什么都没有”
函数
f
用于
C
代码:

var a=Library.f(5);
如何为数据构造函数匹配结果值
a
?比如:

/*
(如果a是左x)
用x做点什么
(如果a正确,则为y)
和我做点什么
*/
使用F#区别于C#的联合有点不雅观,因为它们是如何编译的

我认为最好的方法是定义一些成员(在F#端),以简化使用C#中的类型。有多种选择,但我更喜欢的是定义
TryLeft
TryRight
方法,它们的行为类似于
Int32.TryParse
(因此,使用F#API的C#开发人员应该熟悉它们):

open System.Runtime.InteropServices
类型=
|a的左边
|b的权利
成员x.TryLeft([]a:byref)=
将x与右v匹配->b为假
然后您可以使用C#中的类型,如下所示:

int a;
string s;
if (v.TryLeft(out a)) Console.WriteLine("Number: {0}", a);
else if (v.TryRight(out s)) Console.WriteLine("String: {0}", s);
这样做会失去一些F#安全性,但这在没有模式匹配的语言中是意料之中的。但好的是,熟悉.NET的任何人都应该能够使用在F#中实现的API

另一种选择是定义成员
Match
,该成员接受
Func
委托,并使用左/右大小写携带的值调用右委托。从功能的角度来看,这有点好,但对于C#调用者来说可能不太明显。

从以下方面:

8.5.4从其他CLI语言使用的联合类型的编译形式

已编译的联合类型U具有:

  • 一个CLI静态getter属性U.C用于每个null联合案例C。此属性获取一个表示每个此类案例的单例对象
  • 每个非空联合用例C对应一个CLI嵌套类型U.C。此类型具有实例属性Item1、Item2。。。。对于联盟的每个领域 大小写,如果只有一个字段,则为单个实例属性项。 但是,只有一个大小写的已编译联合类型没有 嵌套类型。相反,联合类型本身起着案例的作用 类型

  • 一个CLI静态方法U.NewC用于每个非空union案例C。此方法为该案例构造一个对象

  • 每个案例C有一个CLI实例属性U.IsC。此属性针对案例返回true或false
  • 每个案例C对应一个CLI实例属性U.标记。此属性获取或计算与案例对应的整数标记
  • 如果U有多个case,则它有一个CLI嵌套类型U.Tags。U.Tags类型包含每种情况下的一个整数文本,以递增形式表示 从零开始的顺序

  • 编译的联合类型具有实现其自动生成的接口所需的方法,以及任何 用户定义的属性或方法

  • 这些方法和属性不能直接从F#使用。 但是,这些类型具有面向用户的List.Empty、List.Cons、, Option.None和Option.Some属性和/或方法

    已编译的联合类型不能用作其他CLI中的基类型 语言,因为它至少有一个程序集专用构造函数和 没有公共构造函数

    如果您无法更改F#api,那么使用上面的第2点和第4点,您可以这样做:

    C#

    F#


    此解决方案很方便,因为它还通过为元组中的每个项创建新属性来处理元组DU情况。

    我将定义一个
    匹配成员,在每个场景中执行代理。在F#中,您可以这样做(但如果需要,您可以在C#扩展方法中做一些等效的事情):

    type one=| a的左边| b的右边
    具有
    
    请记住,该解决方案有一些限制。比如,您不能执行类似
    a.Match的操作(ifLeft:x=>x+1,ifRight:=>returnnull)
    
    class Program
    {
        static void Main(string[] args)
        {
            PrintToConsole("5");
            PrintToConsole("test");
        }
    
        static void PrintToConsole(string value)
        {
            var result = test.getResult(value);
            if (result.IsIntValue) Console.WriteLine("Is Int: " + ((test.DUForCSharp.IntValue)result).Item);
            else Console.WriteLine("Is Not Int: " + ((test.DUForCSharp.StringValue)result).Item);
        }
    }
    
    namespace Library1
    
    module test =
    
        open System
    
        type DUForCSharp =
        | IntValue of int
        | StringValue of string
    
        let getResult x =
            match Int32.TryParse x with
            | true, value -> IntValue(value)
            | _ -> StringValue(x)