sta*_*ica 7 c# f# interface algebraic-data-types discriminated-union
首先,对于冗长的帖子感到抱歉.基本上,我的问题是:
我试图在C#中重现以下F#区别联合类型:
type Relation =
| LessThan of obj * obj
| EqualTo of obj * obj
| GreaterThan of obj * obj
Run Code Online (Sandbox Code Playgroud)
任何人都可以建议一个比以下更简单的基于接口的解决方案?
interface IRelation // concrete types represent ? in the expression "Subject ? Object"
{
object Subject { get; }
object Object { get; }
}
struct LessThanRelation : IRelation { … }
struct EqualToRelation : IRelation { … }
struct GreaterThanRelation : IRelation { … }
Run Code Online (Sandbox Code Playgroud)
我的所有算法都识别这三种关系类型,而这些只是这些,所以我需要阻止IRelation第三方(即其他程序集)的任何进一步实现.
脚注:对某些人来说,如果我只是在面向对象/多态性方面得到了我的接口和算法,那么可能会出现第三方实现被注入到我的算法方法中并不重要,只要接口是正确实施.这是一个有效的批评.但是,让我们假设,在这种情况下,我倾向于在严格的面向对象上采用更多功能编程风格.
我的最好的办法,到目前为止是宣布所有以上类型的internal(即它们将永远不会被外人直接看到.),并创建一个代理类型Relation,这将是唯一可见的类型的第三方:
public struct Relation // constructors etc. are omitted here for brevity's sake
{
public RelationType Type { get { … /* concrete type of value -> enum value */ } }
public Relation Subject { get { return value.Subject; } }
public Relation Object { get { return value.Object; } }
internal readonly IRelation value;
}
public enum RelationType
{
LessThan,
EqualTo,
GreaterThan
}
Run Code Online (Sandbox Code Playgroud)
到目前为止一切都很好,但它更精细......
...如果我公开具体关系类型的工厂方法:
public Relation CreateLessThanRelation(…)
{
return new Relation { value = new LessThanRelation { … } };
}
Run Code Online (Sandbox Code Playgroud)...每当我公开处理关系类型的算法时,因为我必须从/向代理类型映射:
public … ExposedAlgorithm(this IEnumerable<Relation> relations)
{
// forward unwrapped IRelation objects to an internal algorithm method:
return InternalAlgorithm(from relation in relations select relation.value);
}
Run Code Online (Sandbox Code Playgroud)Mar*_*ell 13
限制接口实现意味着它不是真正充当接口(它应该接受任何实现(替换),例如装饰器) - 所以我不能推荐它.
另外,请注意,除了泛型之外,将结构视为接口会导致装箱.
这留下了一个有趣的案例; 带有私有构造函数的抽象类,以及作为嵌套类型的已知数量的实现,这意味着它们可以访问私有构造函数.
现在你控制子类型,装箱不是问题(因为它是一个类),并且对替换的期望较少.
我认为您的一般方法正朝着正确的方向发展,但看起来您可以使用抽象类来简化代码:
public abstract class Relation
{
internal Relation(object subject, object obj)
{
Subject = subject;
Object = obj;
}
public object Subject { get; private set; }
public object Object { get; private set; }
}
public sealed class LessThanRelation : Relation
{
public LessThanRelation(object subject, object obj) : base(subject, obj) { }
}
public sealed class EqualToRelation : Relation
{
public EqualToRelation(object subject, object obj) : base(subject, obj) { }
}
public sealed class GreaterThanRelation : Relation
{
public GreaterThanRelation(object subject, object obj) : base(subject, obj) { }
}
Run Code Online (Sandbox Code Playgroud)
外部程序集可以看到除了内部构造函数之外的所有Relation类成员- 从外部看,它看起来该类没有定义构造函数,因此第三方程序集不可能定义自己的实现.