0

我已经构建了一个自定义类型系统,用于在应用程序内的 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基类。这样,已经可以消除一部分显式强制转换。我在这个基类中实现了一些运算符重载,但这给默认转换运算符带来了很多麻烦……除此之外,在运算符实现中实现的逻辑涉及到很多关于系统类型的知识。我认为这在某种程度上仍然是一个人必须走的路,但是要遵循什么规则,以一种好的和安全的方式实施呢?

编辑:经过一段时间的努力,我能找到的一些规则是:

  • 仅隐式声明来自基本类型(int、double、string、...)的转换运算符
  • 显式声明到基本类型的转换(以避免隐式转换为 int!经常发生这种情况,但为什么?)
  • 为避免模棱两可的调用,不应在基类和派生类中重写 +、-、/、* 运算符。【那该怎么走呢?我在派生类中进行了操作重载,这需要在使用时进行强制转换,这又是丑陋的......]
4

1 回答 1

1

如果你应该能够Add对所有IValue的s进行操作,也许接口应该包含一个Add方法?然后你可以做return a.Add(b);,并将如何执行操作的知识推送到每种类型中。

一个问题是,现在看起来,您可能会接到电话 where aisRefStringbis RefInteger,这可能不是您想要的。泛型可以帮助解决这个问题:

T Add<T>(T a, T b) where T : IValue
{
    return a.Add(b);
}

(当然你需要添加空检查和适当的)

于 2010-11-01T19:26:42.370 回答