我已经构建了一个自定义类型系统,用于在应用程序内部使用C#脚本。这些脚本是即时编译的,允许与应用程序内部数据进行交互。此类型系统使用IValue
之类的接口以抽象方式设计。 IValue
的实施可以是RefString
,RefInteger
,RefDouble
(在许多其他方面,但这足以证明我的问题)。
现在我们陷入了困境......使用这些IValue
对象有点不自然。始终使用接口与对象进行交互被认为是一种很好的设计,但是不可能为接口定义隐式转换或重载操作符。这就产生了丑陋的显式转换是不可避免的情况,以便使用正确的操作符。
示例:
IValue Add(IValue a, IValue b)
{
//return a+b; // won't work: which operator +() to use?
return (RefInteger)a + (RefInteger)b;
}
对于涉及值类型的表达式中的C#,提供了隐式转换。设计这样一个自定义系统的好方法是什么?
我重写了类型系统,删除了IValue
接口并引入了RefValue
基类。这种方式已经可以消除显式转换的一部分。我在这个基类中实现了一些运算符重载,但这给默认的转换运算符带来了很多麻烦......除此之外,在运算符实现中实现的逻辑暗示了很多关于系统中类型的知识。我认为这仍然是人们必须走的方式,但要遵循哪些规则,以良好和安全的方式实施这一点?
编辑:经过一段时间的努力,我能找到的一些规则是:
答案 0 :(得分:1)
如果您应该能够对所有Add
进行IValue
操作,那么界面是否应该包含Add
方法?然后你可以做return a.Add(b);
,并将如何执行操作的知识推送到每种类型。
现在看来,有一个问题是,a
RefString
b
和RefInteger
为T Add<T>(T a, T b) where T : IValue
{
return a.Add(b);
}
时,您可能会拨打电话,这可能不是您想要的。泛型可以帮助解决这个问题:
{{1}}
(当然你需要添加空检查和适当的)