Creating your own primitive type

It’s a very rare requirement, but sometimes in .NET you have to create your own primitive and make it behave as close as possible to a native CTS (common type system) type. “That shouldn’t be hard” would be your first thought, until you start considering all the scenarios in which it could be used.

I would very much advise against creating your own primitive type and instead reuse one of the built in types. If none of the built-in types provide the functionality you are after try searching for a nuget. Only when you have exhausted the previous two options then start thinking whether it’s worth it and may be there’s a legitimate reason that type doesn’t exist.

Creating a custom type is fairly simple, but then you need to consider the following:
  • Whether you want to make it COM visible
  • How the type is going to perform serialization
  • Whether its string representation should be customizable
  • Providing all the operator overloads so it behaves like a built in type.
  • Implicit and explicit conversions
  • Comparison to other types
  • Equality
  • Persistence to various databases
  • WCF/Remoting behaviour
Soon, something which you thought should take no more than 20 lines of code, could well exceed several thousands lines of code!
I once had to implement a Fraction type. I did so by having two fields of type long to accommodate the necessary precision: numerator and denominator (since most of the CPU nowadays are 64 bit using an int32 would unlikely bring any performance benefits).

Be prepared for a lot of “boring” code. What really helped me to organise the code was the use of partial classes. I would have a partial class for each interface or specific functionality I was trying to implement. For example all the operator methods would go into a separate file Function.Operators.cs.

One thing to consider when writing operations methods is that each operations method should also be exposed as a simple static method to ensure maximum compatibility with languages other than C#, that essentially doubles your source code for operations.

Then I would do the same for each of the interfaces it had to implement. And there are a lot of them if you want your type to be at home in .NET:

[StructLayout(LayoutKind.Sequential)]

[Serializable]
public readonly partial struct Fraction :
IEquatable<Fraction>,
IEquatable<long>,
IEquatable<float>,
IEquatable<double>,
IEquatable<decimal>,
IComparable<Fraction>,
IComparable<long>,
IComparable<float>,
IComparable<double>,
IComparable<decimal>,

IConvertible

Bear in mind that I didn’t have to care about it being used from COM, otherwise I would have had to add another attribute [ComVisible(true)] and then deal with consequences of having to make it usable from COM.
I also had to provide some default values for the type, similar to what you would find in double, float, int etc:
public static readonly Fraction Zero = new Fraction(0, 1);
public static readonly Fraction One = new Fraction(1, 1);
public static readonly Fraction MinusOne = new Fraction(-1, 1);
public static readonly Fraction SmallestFraction = new Fraction(1, long.MaxValue);
public static readonly Fraction Pi = new Fraction(3126535, 995207);

public const long LargestDenominatorThanCanBeReduced = 3037000499;

Obviously the code was fully covered in unit and performance tests to ensure you don’t break anything along the way and don’t introduce a change that negatively impacts the performance.

Because it was for one of the clients I simply cannot take the code I have written. I have to rewrite the code from memory all over again. I think I’m 50% there.

To give you a feeling for what it takes have a look at the repository on github: https://github.com/ebalynn/Balynn.Maths.Fraction and bear in mind it’s only 50% done

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: