Question

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

Was it helpful?

Solution

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

OTHER TIPS

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.

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.

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
{
}

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top