繁体   English   中英

C# 如何以函数式风格实现多态性?

[英]C# How to implement polymorphism in a functional style?

我有一些 OOP 代码,我想将其转换为功能样式,仅使用不可变类型且仅具有独立( static )无副作用功能。

这是一个场景的简化版本:

abstract class Thing { }

class Sphere : Thing {
    public readonly double Radius;
     public Sphere(double r) { Radius = r; }
}

class Cube : Thing {
     public readonly double Side;
     public Cube(double s) { Side = s; }
}

之前, Thing定义了一个抽象方法void Grow(double ratio) 我已将这两个具体实现转换为独立的 static 函数:

Sphere Grow(Sphere s, double ratio) => new Sphere(s.Radius*ratio);
Cube Grow(Cube c, double ratio) => new Cube(c.Side * ratio);

在 OOP 版本中,我可以使用多态性来枚举类型Thing的集合并导致每个对象增长,例如:

things.foreach(x => x.Grow(r));

但是我怎样才能在函数式方法中做到这一点呢? 我知道我可以这样写:

Thing Grow(Thing t, double ratio) => t switch
{
     Sphere s => Grow(s, ratio),
     Cube c => Grow(c, ratio),
     _ => throw new Exception()
};

things.Select(t => Grow(t, r))

但我不喜欢必须为我添加的每个新的 Thing 实现扩展 switch 表达式的想法。

我可以看到一种方法(我认为)使用反射来做到这一点,但出于其他原因我并不热衷于此。

有没有更简单的方法可以使用功能模式实现等效的 OOP 多态性? (在 C# 中,即 - 我知道它可以在例如 Haskell 中完成)。

尝试像这样为Grow方法定义和使用通用接口。

interface IGrowable<T> where T: Thing { 
    T Grow(T t, double ratio);
}

class Sphere : Thing, IGrowable<Sphere> {
    public readonly double Radius;
    public Sphere(double r) { Radius = r; }
    public Sphere Grow(Sphere s, double ratio) => new Sphere(s.Radius*ratio);

}

class Cube : Thing, IGrowable<Cube> {
     public readonly double Side;
     public Cube(double s) { Side = s; }
     public Cube Grow(Cube c, double ratio) => new Cube(c.Side * ratio);
}
IEnumerable<IGrowable<T>> GrowOwn<T>(IEnumerable<IGrowable<T>> grows, double ratio){
    return grows.Select(x => x.Grow(x,ratio));
}

编辑

如果要使用反射,定义这些 class

public abstract class Thing {}

public class Sphere : Thing {
    public readonly double Radius;
    public Sphere(double r) { Radius = r; }
    public Sphere(Sphere s, double ratio){ Radius = s.Radius * ratio; }
}

public class Cube : Thing {
     public readonly double Side;
     public Cube(double s) { Side = s; }
     public Cube(Cube c, double ratio){ Side = c.Side * ratio; }
}

和这个。

T Grow<T>(T thing, double ratio) where T: Thing => (T)Activator.CreateInstance(typeof(T) , thing,  ratio);

您可以从此 function 获得Thing object。
但是存在MissingMethodException的风险。 而且反射不快。
请参阅 .NET 的设计目标,使用表达式树可能有助于提高处理速度)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM