可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to write generic Vector2 type which would suite float, double, etc. types and use arithmetical operations. Is there any chance to do it in C#, F#, Nemerle or any other more or less mature .NET language?
I need a solution with
- (1)good performance (same as I would have writing separate
Vector2Float, Vector2Double, etc. classes),
- (2)which would allow
code to look nice (I do not want to emit code for each class in
run-time)
- (3)and which would do as much compile time checking as possible.
For reasons 1 and 3 I would not like to use dynamics. Right now I am checking F# and Nemerle.
UPD: I expect to have a lot of mathematical code for this type. However, I would prefer to put the code in extension methods if it is possible.
UPD2: 'etc' types include int(which I actually doubt I would use) and decimal(which I think I might use, but not now). Using extension methods is just a matter of taste - if there are good reasons not to, please tell.
回答1:
As mentioned by Daniel, F# has a feature called statically resolved type arguments which goes beyond what you can do with normal .NET generic in C#. The trick is that if you mark function as inline
, F# generates specialized code automatically (a bit like C++ templates) and then you can use more powerful features of the F# type system to write generic math.
For example, if you write a simple add function and make it inline
:
let inline add x y = x + y;;
The type inference prints the following type:
val inline add :
x: ^a -> y: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
You can see that the inferred type is fairly complex - it specifies a member constraint that requires one of the two arguments to define a +
member (and this is also supported by standard .NET types) The good thing is that this can be fully inferred, so you will rarely have to write the ugly type definitions.
As mentioned in the comments, I wrote an article Writing generic numeric code that goes into more details of how to do this in F#. I don't think this can be easily done in C# and the inline functions that you write in F# should only be called from F# (calling them from C# would essentially use dynamic). But you can definitely write your generic numerical computations in F#.
回答2:
This more directly addresses your previous question. You can't put a static member constraint on a struct, but you can put it on a static
Create
method.
[<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)
回答3:
C# alone will not help you in achieving that, unfortunately. Emitting structs at run-time wouldn't help you much either since your program couldn't statically refer to them.
If you really can't afford to duplicate the code, then as far as I know, "offline" code generation is the only way to go about this. Instead of generating the code at runtime, use AssemblyBuilder
and friends to create an on-disk assembly with your Vector2 types, or generate a string of C# code to be fed to the compiler. I believe some of the native library wrappers take this route (ie OpenTK
, SharpDX
). You can then use ilmerge
if you want to merge those types to one of your hand-coded libraries.
I'm assuming you must be coming from a C++ background where this is easily achieved using templates. However, you should ask yourself whether you actually need Vector2 types based on integral, decimal and other "exotic" numeric types. You probably won't be able to parameterize the rest of your code based on a specific Vector2 either so the effort might not be worth it.
回答4:
Look into inline functions and Statically Resolved Type Parameters.
回答5:
As I understand you a strict type in the compile time , but you don't care what happens in the runtime.
Nemerle language currently doesn't support this construction as you want.
But it supports macros and allows you writing DSLs to generate arbitrary code.
For instance you can do some macro which analyzes this code and transforms it to the correct type.
def vec = vector { [1,2] };
Assuming we have or create a type VectorInt the code could be translated to
def vec = VectorInt(1,2);
Of course you can write any code inside and transform it to any code you want :)
Operators can be implemented as usual operators of the class.
Nemerle also allows you to define any operators like F#.
回答6:
make use of Generics , this makes is also type safe
more info on generics : http://msdn.microsoft.com/en-us/library/512aeb7t.aspx
But you also have availible datastructures such as List and Dictionary
Sounds like you want operator overloading, there are a lot of examples for this. There is not realy a good way to only allow decial, float and such. The only thing you can do is restrict to struct, but thats not exactly what you want.