我正在尝试编写通用的Vector2类型,它将包含float,double等类型并使用算术运算。有没有机会在C#,F#,Nemerle或任何其他或多或少成熟的.NET语言中做到这一点?
我需要一个
的解决方案由于原因1和3,我不想使用动态。现在我正在检查F#和Nemerle。
UPD:我希望这种类型有很多数学代码。但是,如果可能的话,我更愿意将代码放在扩展方法中。
UPD2:'etc'类型包括int(我实际上怀疑我会使用)和decimal(我想我可以使用,但现在不是)。使用扩展方法只是一个品味问题 - 如果有充分理由不这样做,请告诉我们。
答案 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)
如果你真的无法复制代码,那么据我所知,“离线”代码生成是解决这个问题的唯一方法。不要在运行时生成代码,而是使用AssemblyBuilder
和朋友使用Vector2类型创建磁盘上的程序集,或者生成一串C#代码以供给编译器。我相信一些本地库包装器采用这种方式(即OpenTK
,SharpDX
)。如果要将这些类型合并到一个手动编码库中,则可以使用ilmerge
。
我假设您必须来自C ++背景,这可以使用模板轻松实现。但是,你应该问自己,你是否真的需要基于积分,十进制和其他“奇异”数字类型的Vector2类型。您可能无法根据特定的Vector2参数化其余代码,因此可能不值得。
答案 3 :(得分:1)
答案 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
但您也有可用的数据结构,例如List和Dictionary
听起来像你想要operator overloading,这里有很多例子。没有一个好方法只允许decial,float等。你唯一能做的就是限制结构,但那不完全是你想要的。