C#中的显式方法表而不是OO - 好吗?坏?

Fun*_*lad 3 c# oop generics polymorphism functional-programming

我希望标题听起来不太主观; 我绝对不是要开始就OO进行辩论.我只想讨论解决以下问题的不同方法的基本利弊.

让我们来看一个这个最小的例子:你想表达一个抽象数据类型T,其函数可以将T作为输入,输出或两者:

  • f1:取一个T,返回一个int
  • f2:取一个字符串,返回一个T.
  • f3:取T,返回另一个T.

我想避免向下转发和任何其他动态类型.我也想尽可能避免变异.

1:基于抽象类的尝试

abstract class T {
  abstract int f1();
  // We can't have abstract constructors, so the best we can do, as I see it, is:
  abstract void f2(string s);
  // The convention would be that you'd replace calls to the original f2 by invocation of the nullary constructor of the implementing type, followed by invocation of f2. f2 would need to have side-effects to be of any use.

  // f3 is a problem too:
  abstract T f3(double d);
  // This doesn't express that the return value is of the *same* type as the object whose method is invoked; it just expresses that the return value is *some* T.
}
Run Code Online (Sandbox Code Playgroud)

2:参数多态和辅助类

(所有实现的TImpl类都是单例类):

abstract class TImpl<T> {

  abstract int f1(T t);

  abstract T f2(string s);

  abstract T f3(T t, double d);

}
Run Code Online (Sandbox Code Playgroud)

我们不再表示某些具体类型实际上实现了我们的原始规范 - 实现只是一个类型Foo,我们碰巧有一个TImpl实例.这似乎不是一个问题:如果你想要一个适用于任意实现的函数,你只需执行以下操作:

// Say we want to return a Bar given an arbitrary implementation of our abstract type
Bar bar<T>(TImpl<T> ti, T t);
Run Code Online (Sandbox Code Playgroud)

在这一点上,人们可以完全跳过继承和单身人士并使用

3一流的功能表

class /* or struct, even */ TDict<T> {
  readonly Func<T,int> f1;
  readonly Func<string,T> f2;
  readonly Func<T,double,T> f3;

  TDict( ... ) {
    this.f1 = f1;
    this.f2 = f2;
    this.f3 = f3;
  }
}

Bar bar<T>(TDict<T> td; T t);
Run Code Online (Sandbox Code Playgroud)

虽然我没有看到#2和#3之间有太大的实际区别.

示例实现

class MyT { 
  /* raw data structure goes here; this class needn't have any methods */
}

// It doesn't matter where we put the following; could be a static method of MyT, or some static class collecting dictionaries
static readonly TDict<MyT> MyTDict 
  = new TDict<MyT>(
      (t) => /* body of f1 goes here */ ,
      // f2
      (s) => /* body of f2 goes here */,
      // f3
      (t,d) => /* body of f3 goes here */
    );
Run Code Online (Sandbox Code Playgroud)

思考?#3是单一的,但似乎相当安全和干净.一个问题是它是否存在性能问题.我通常不需要动态调度,我更喜欢这些函数体在静态地知道具体实现类型的地方静态内联.在这方面#2更好吗?

C. *_*ann 10

Hurm.所以,让我看看我是否理解这一点:在具有隐式初始参数ad-hoc多态的OOP语言中,您希望使用参数多态来通过显式 ad-hoc多态来推动您自己的准OO系统改进的方法字典,所有这些都是为了允许被调度的类型出现在函数签名的其他地方而不是隐式this参数.你想知道这是不是一个好主意.

从您的用户名我敢肯定,你知道得很清楚,你真正想要的是类型类一拉 Wadler 等.仅仅因为微软签署SPJ的薪水并不意味着用C#编写Haskell是个好主意.

你的代码对于理解所表达成语的人来说非常清楚,但是它远远超出了OOP风格的主流,你要确保简洁和正确的收益值得使用外国成语的缺点,例如混淆其他C#程序员.我还建议通过分析一些概念验证代码来处理性能问题,因为这种风格与大多数C#程序中的风格相差甚远.

另一方面,找到表达外国习语的简洁方法本质上并不是邪恶的 - 比较代数数据类型与访问者模式的比较 - 所以如果你需要具有这些属性的代码,那么这是表达的最佳方式它,留下关于代码背后的意图的一些注释并去寻找它.

简而言之:确保它解决您的问题,测试和配置文件以确保它不会导致其他问题,然后为其他程序员记录并解释解决方案.