views:

149

answers:

6

How to easily/quickly replace float's for doubles (for example) for compiling to two different targets using these two particular choices of primitive types?

Discussion: I have a large amount of c# code under development that I need to compile to alternatively use float, double or decimals depending on the use case of the target assembly.

Using something like “class MYNumber : Double” so that it is only necessary to change one line of code does not work as Double is sealed, and obviously there is no #define in C#. Peppering the code with #if #else statements is also not an option, there is just too much supporting Math operators/related code using these particular primitive types.

I am at a loss on how to do this apparently simple task, thanks!

Edit: Just a quick comment in relation to boxing mentioned in Kyles reply: Unfortunately I need to avoid boxing, mainly since float's are being chosen when maximum speed is required, and decimals when maximum accuracy is the priority (and taking the 20x+ performance hit is acceptable). Boxing would probably rules out decimals as a valid choice and defeat the purpose somewhat.

Edit2: For reference, those suggesting generics as a possible answer to this question note that there are many issues which count generics out (at least for our needs). For an overview and further references see Using generics for calculations

A: 

At worst I think you could use boxing and something like this:

#if USE_FLOAT
public float OutputValue(object input)
{
    return (float)input;
}
#endif

#if USE_DOUBLE
public double OutputValue(object input)
{
    return (double)input;
}
#endif

and call OutputValue(1.5); to get it to convert it for you.

Andrew Koester
Unfortunately I need to avoid boxing, mainly since float's are being chosen when maximum speed is required, and decimals when maximum accuracy is the priority and taking the 20x+ performance hit is acceptable. Boxing would probably rules out decimals as a valid choice. Thanks for the suggest ion though - I will address this in the main question.
Keith
A: 

One approach would be to have a generic around the base type you need. Then you declare a class that inherits specific instance of that generic in a separate .cs file and you create three copies of this class for each base type you need. Then you change your .csproj to include the proper .cs file based on the build configuration.

Note that I have not really tried this, so there might be couple of kinks to iron out.

Franci Penov
A: 

You could do this:

public struct NumberContainer<T> 
{
    T _number;

    // accessor, and possibly: operators, cast methods, etc.
}

And then:

#if USE_FLOAT
public struct MyNumber : NumberContainer<float>
#else
public struct MyNumber : NumberContainer<double>
#endif
{
}
Ben M
Uuuh... I don't like this solution, it turns what you would normally expect to be a value type into a reference type. Is there a reason you didn't make NumberContains<T> a struct?
LorenVS
Also, the inheritance chain is unnecssary as you can use:#if USE_FLOATusing MyNumber = NumberContains<float>#endifand then make NumberContainer non-abstract
LorenVS
Sorry, yeah, a struct would be better... was thinking about the main construct rather than the details. Edited.
Ben M
True, but then you have to do #if/using in every file--which is a pain.
Ben M
Yeah, I'm trying to think of a way to get around the #if in every file but I'm not having much luck
LorenVS
I think the advantages of your solution far outweigh the annoyance of having to put it in every file.
Ben M
+6  A: 

The best way to do this would be using #if as Andrew stated above. However, an interesting idea to think about would be something like this:

#if USE_FLOAT
using Numeric = System.Single;
#endif

#if USE_DOUBLE
using Numeric = System.Double;
#endif

#if USE_DECIMAL
using Numeric = System.Decimal;
#endif

public class SomeClass
{
    public Numeric MyValue{get;set;}
}

EDIT:

I still really like this solution, it allows you to do some other really cool things such as:

Numeric.Parse();
Numeric.TryParse();

Which will work for all three types

LorenVS
I started thinking about a Generics solution, then I saw this. So simple. Duh.
x0n
Looks good, very simple! I''l give it a go and get back to you...
Keith
Yeah: the only real disadvantage is that you have to put this construct in all of your files; but this is definitely outweighed by the fact that you can treat variables declared in this way as though you were using the original type names. +1
Ben M
After thinking about the file issue for a while, the best I can come up with is surround the whole thing in a #region, minimize it and forget about it... nothing much else that can be done, bit of a shame
LorenVS
It's not possible to put that construct in a separate file and import it or something?Also, should maybe use `#elif` or something on the second two?
Svish
A: 

This is difficult, since the basic types do not impelment something like IArithmetic. This has been suggested many times on Connect. Unfortunately, this is a well known limitation of generics.

There are some workarounds, using a "calculator" struct class. If the math isn't too onerous that's being done, this works very, very well.

However, it's clunky. This is one place where generics are not as flexible as C++ templates.

One other approach could be to use something like the Text Template Transformation Toolkit (T4) to generate a template that would work with any type, and compile separate ones per type.

Reed Copsey
A: 

would something like this work?

    [STAThread]
    public static void Main()
    {
        var x = InitValue();
        var y = InitValue();
        var z = InitValue();
    }


    public static double InitValue()
    {
        return 0;
    }

By using "var" you can just simply change the return type on "InitValue" and suddenly all of your doubles are now something else.

DataDink