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

时间:2018-04-21 05:11:22

标签: c# generics f# functional-programming polymorphism

我的抽象目标是:

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

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

3)当User选择特定类型的方法时,他应该被迫根据所选类型插入正确类型的其他参数(如键),并且应该在编译时验证(将键作为对象传递) type要求对象的“真实”类型进行运行时评估。

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
  } 
}

用户可以像以下一样使用它:

Add(new Invoice(), inv=> { inv.field1 = "123"; ... return inv;})

在功能样式中解决此问题的好方法是什么(例如在F#中)?

1 个答案:

答案 0 :(得分:1)

在函数式编程中,您可以使用泛型 http://app2.dev/解决该问题。通常,您会决定处理“命令”原语,例如:

data Command a b c = Command(a -> Either b c)

由您决定在命令的特殊性,通用参数的数量和通用(输入-输出)接口之间找到合适的平衡:尽管algebraic types是经典选择,也可以在F#中使用;另一种常用的类型是Either,也由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 -> Either b c, b -> Either e d)来解决,该类型在内部将依赖于{{1} }的单链绑定以链接这两个功能。