如何避免在.NET中为不同的数字类型编写重复代码

时间:2014-02-25 12:45:55

标签: c# f# numbers dry nemerle

我正在尝试编写通用的Vector2类型,它将包含float,double等类型并使用算术运算。有没有机会在C#,F#,Nemerle或任何其他或多或少成熟的.NET语言中做到这一点?

我需要一个

的解决方案
  • (1)表现良好(与我单独写作相同 Vector2Float,Vector2Double等课程,
  • (2)允许 代码看起来不错(我不想为每个类发出代码 运行时间)
  • (3)并且尽可能多地进行编译时检查。

由于原因1和3,我不想使用动态。现在我正在检查F#和Nemerle。

UPD:我希望这种类型有很多数学代码。但是,如果可能的话,我更愿意将代码放在扩展方法中。

UPD2:'etc'类型包括int(我实际上怀疑我会使用)和decimal(我想我可以使用,但现在不是)。使用扩展方法只是一个品味问题 - 如果有充分理由不这样做,请告诉我们。

6 个答案:

答案 0 :(得分:8)

正如Daniel所说,F#有一个名为静态解析类型参数的功能,它超出了你在C#中使用普通.NET泛型的功能。诀窍在于,如果将函数标记为inline,F#会自动生成专用代码(有点像C ++模板),然后您可以使用F#类型系统的更强大功能来编写泛型数学。

例如,如果您编写一个简单的添加函数并将其设为inline

let inline add x y = x + y;;    

类型推断打印以下类型:

val inline add :
  x: ^a -> y: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

你可以看到推断类型相当复杂 - 它指定了一个成员约束,它需要两个参数之一来定义一个+成员(这也是标准.NET类型支持的)好东西这是可以完全推断的,因此您很少需要编写丑陋的类型定义。

正如评论中所提到的,我写了一篇文章Writing generic numeric code,详细介绍了如何在F#中做到这一点。我不认为这可以在C#中轻松完成,并且您在F#中编写的内联函数只能从F#调用(从C#调用它们本质上将使用动态)。但你绝对可以用F#编写通用数值计算。

答案 1 :(得分:3)

这更直接地解决了您之前的问题。您不能在结构上放置静态成员约束,但可以将其放在static Create方法上。

[<Struct>]
type Vector2D<'a> private (x: 'a, y: 'a) =
  static member inline Create<'a  when 'a : (static member (+) : 'a * 'a -> 'a)>(x, y) = Vector2D<'a>(x, y)

答案 2 :(得分:1)

不幸的是,单独使用C#无法帮助您实现这一目标。由于您的程序无法静态引用它们,因此在运行时发出结构对您没有多大帮助。

如果你真的无法复制代码,那么据我所知,“离线”代码生成是解决这个问题的唯一方法。不要在运行时生成代码,而是使用AssemblyBuilder和朋友使用Vector2类型创建磁盘上的程序集,或者生成一串C#代码以供给编译器。我相信一些本地库包装器采用这种方式(即OpenTKSharpDX)。如果要将这些类型合并到一个手动编码库中,则可以使用ilmerge

我假设您必须来自C ++背景,这可以使用模板轻松实现。但是,你应该问自己,你是否真的需要基于积分,十进制和其他“奇异”数字类型的Vector2类型。您可能无法根据特定的Vector2参数化其余代码,因此可能不值得。

答案 3 :(得分:1)

查看内联函数和Statically Resolved Type Parameters

答案 4 :(得分:0)

正如我在编译时理解你的严格类型,但你不关心运行时会发生什么。 Nemerle语言目前不支持您想要的这种结构。 但它支持宏,并允许您编写DSL以生成任意代码。 例如,您可以执行一些宏来分析此代码并将其转换为正确的类型。

def vec = vector { [1,2] };

假设我们已经或创建了一个VectorInt类型,代码可以转换为

def vec = VectorInt(1,2);

当然,您可以在里面编写任何代码并将其转换为您想要的任何代码:)

操作符可以像该类的常用操作符一样实现。 Nemerle还允许您定义任何运算符,如F#。

答案 5 :(得分:-2)

使用泛型,这也是类型安全的

有关泛型的更多信息:http://msdn.microsoft.com/en-us/library/512aeb7t.aspx

但您也有可用的数据结构,例如ListDictionary

听起来像你想要operator overloading,这里有很多例子。没有一个好方法只允许decial,float等。你唯一能做的就是限制结构,但那不完全是你想要的。