Cou*_*ren 5 c# generics polymorphism f# functional-programming
我的抽象目标是:
1)创建一个CRUD API,它是带有CRUD接口的第三方库的包装器(可以来自服务对象和/或实体对象)
2)每个CRUD方法应根据预定义的类型定义限制输入的类型(一种类型可以输入多种方法)
3)当用户选择特定类型的方法时,他应该被迫根据所选类型插入正确类型的其他参数(如键),并且应该在编译时验证这些参数(将键作为对象类型传递需要运行时)评估对象的"真实"类型.
4)方法的类型是第三方接口,不在我的控制之下,我无法改变它们.
5)API对于用户来说应该是直截了当的,并且用户的样板代码量较少.
我发现在C#中解决这个问题的一种方法是:
public interface Update<T,TKey> {}
public interface Add<T> {}
public interface Delete<T,TKey> {}
public interface Get<T,TKey> {}
public class Invoice:Get<string>, Add<ThirdPartyInvoice>, Update<ThirdPartyInvoice,string> {}
//More types can come here...
public static class CRUDAPI
{
public static T Get<T,TKey>(Get<T,TKey> type, TKey key)
{
//will get a T from a service object based on TKey
}
public static Unit Add<T>(Add<T> type, Func<T,T> select)
{
//will get a new instance of T and will feed it to the select function.
//and then will feed the result to the 3rd party add method
}
public static Unit Update<T,TKey>(Update<T,TKey> type,TKey key, Func<T,T> select)
{
//will load an instance of T and will feed it to the select function.
//and then will feed the result to the 3rd party update method
}
public static Unit Delete<T,TKey>(Delete<T,TKey> type,TKey key)
{
//will load an instance of T and then will use 3rd party delete method
}
}
Run Code Online (Sandbox Code Playgroud)
然后用户可以使用它:
Add(new Invoice(), inv=> { inv.field1 = "123"; ... return inv;})
Run Code Online (Sandbox Code Playgroud)
什么是以功能样式解决这个问题的好方法(例如在F#中)?
在函数式编程中,您可以使用泛型 代数类型来解决该问题。您通常会决定处理“命令”原语,例如:
data Command a b c = Command(a -> Either b c)
Run Code Online (Sandbox Code Playgroud)
您需要在命令的特殊性、通用参数的数量和通用(输入-输出)接口之间找到适当的平衡:尽管Either是经典选择,也可在 F# 中使用;另一种常用的类型是Maybe,也是由 F# 提供的。
然后你可以定义:
data CRUD a b c d e f = CRUD{ create :: Command a b c, read :: Command d e f, ... }
Run Code Online (Sandbox Code Playgroud)
再次,找到正确的平衡点。
然后你会发现,有很多很多命令。真的。其中一些直接进入数据库,其他负责 DTO -> 模型映射,其他处理验证。您希望以乐高时尚的方式组合它们: ,这可以通过扩展您的代数类型Command a b c -> Command b e d -> Command a e d
来解决: ,它在内部将依赖于的单子绑定来链接这两个函数。Command
... | CompositeCommand(a -> Either b c, b -> Either e d)
Either