Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.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
使用函数技术在F中用泛型重新实现C#继承_C#_Generics_F#_Functional Programming_Polymorphism - Fatal编程技术网

使用函数技术在F中用泛型重新实现C#继承

使用函数技术在F中用泛型重新实现C#继承,c#,generics,f#,functional-programming,polymorphism,C#,Generics,F#,Functional Programming,Polymorphism,我的抽象目标是: 1) 创建一个CRUD API,它是具有CRUD接口的第三方库的包装器(可以来自服务对象和/或实体对象) 2) 每个CRUD方法都应该根据预定义的类型定义限制提供给它的类型(一个类型可以提供给多个方法) 3) 当用户选择方法的特定类型时,应强制用户根据所选类型插入正确类型的其他参数(如键),这些参数应在编译时进行验证(将键作为对象类型传递需要对对象的“真实”类型进行运行时评估) 4) 该方法的类型是不在我控制范围内的第三方接口,我无法更改它们 5) API对于用户来说应该是简单

我的抽象目标是:

1) 创建一个CRUD API,它是具有CRUD接口的第三方库的包装器(可以来自服务对象和/或实体对象)

2) 每个CRUD方法都应该根据预定义的类型定义限制提供给它的类型(一个类型可以提供给多个方法)

3) 当用户选择方法的特定类型时,应强制用户根据所选类型插入正确类型的其他参数(如键),这些参数应在编译时进行验证(将键作为对象类型传递需要对对象的“真实”类型进行运行时评估)

4) 该方法的类型是不在我控制范围内的第三方接口,我无法更改它们

5) API对于用户来说应该是简单的,而样板代码的数量应该更少

我发现在C#中解决这个问题的一种方法是:


在函数式编程中,什么是解决这个问题的好方法(例如在F中)?

在函数式编程中,您可以使用泛型解决这个问题。您通常会决定处理“命令”原语,如:

data Command a b c = Command(a -> Either b c)
要在命令的特殊性、泛型参数的数量和通用(in-out)接口之间找到正确的平衡,这取决于您:虽然这是一个经典的选择,但在F#中也可用;另一种常用类型是,也由F#提供

然后您可以定义:

data CRUD a b c d e f = CRUD{ create :: Command a b c, read :: Command d e f, ... }
再一次,找到正确的平衡点


然后你会发现,有很多很多的命令。真正地其中一些直接进入数据库,另一些负责DTO->模型映射,另一些负责验证。您希望以乐高的方式组合它们:
Command a b c->Command b e d->Command a e d
,这可以通过扩展您的
Command
代数类型来解决:
CompositeCommand(a->b或c,b->e或d)
,它在内部将依赖于
的一元绑定来链接两个函数。

您是否试图重新创建泛型约束?仅使用泛型约束无法获得“类型映射”例如,当我在Get方法中选择Invoice-lets时,TKey将自动被指定为string,而T将被指定为特定对象。换言之,选择一个参数可以很容易地解决另一个参数的类型问题,不过需要传入和传出许多通用参数。F#会做完全相同的事情,不管多么安静:所以程序员只会注意到这一点。泛型在C#中太显式,因此非常有限。我所看到的唯一合理的权衡是“降低一级”并处理精确的通用命令。你也这么做了,但过于简单化了。另一个选项是用F#编写适当的库,并用类似C#的接口将其包装起来。使用您的模型:假设命令a b C应该反映get/read命令(假设b C cocrete类型),我将选择a作为int,b作为invoice,C作为string,现在我想为这个命令表示一个客户端,它应该是a是int,b是client,c是string,我应该为它创建一个新的命令类型并单独实现吗?@CountOren,对不起,我找不到你。请使用适当的格式在英语和代码之间进行双语言。要表示我的域:我是否必须为每个对象定义新类型,例如1)CRUDInvoice字符串ThirdPartyVoice。。。2) CRUDClient int thirdpartyclient…?@CountOren,没有
CRUD
是一个单一的通用接口,可在整个应用程序中重用。您将实现不同类型的
命令
,并将其输入相应的
CRUD
实例。因此,每个
CRUD
实例都应该由不同命令的代数类型(为发票读取,为客户机读取…)构建,或者我应该拥有不同的实例
readInvoice
readClient
data Command a b c = Command(a -> Either b c)
data CRUD a b c d e f = CRUD{ create :: Command a b c, read :: Command d e f, ... }