Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics or multiple classes [duplicate]

Tags:

c#

generics

Right now we have two structs to represent 2d points.

public struct Point2D
{
    public double X { get; set; }
    public double Y { get; set; }
}

public struct Point2DF
{
    public float X { get; set; }
    public float Y { get; set; }
}

Now we need to make another struct to represent 2d point for intergers.

public struct Point2DI
{
    public int X { get; set; }
    public int Y { get; set; }
}

My question is should I use generics here? If I use generics I will have one single struct instead of three.

public struct Point<T>
{
    public T X { get; set; }
    public T Y { get; set; }
}

But consumer can set T as string or some class/struct. What should I do? Is there any way I can force T to be double/int/float?

like image 211
fhnaseer Avatar asked Jan 07 '23 19:01

fhnaseer


1 Answers

I think its better to go for Generics, since this would be much cleaner given you don't need multiple classes, inheritance or any other fancy stuff (which would work too, but IMO it wouldn't be that clean)

Unfortunately there is no constraint for numeric types, so this is what I came up with which comes closest IMO:

public class Point<T>
    where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{

    protected readonly Type[] AllowedTypes = 
        {
            typeof(decimal), typeof(double), typeof(short), typeof(int), typeof(long),
            typeof(sbyte), typeof(float), typeof(ushort), typeof(uint), typeof(ulong)
        };

    public Point()
    {   
        if (!this.AllowedTypes.Contains(typeof(T)))
        {
            throw new NotSupportedException(typeof(T).ToString());
        }           
    }

    public T X { get; set; }

    public T Y { get; set; }

    // UPDATE: arithmetic operations require dynamic proxy-Properties or
    // variables since T is not explicitly numeric... :(
    public T CalculateXMinusY()
    {
        dynamic x = this.X;
        dynamic y = this.Y;

        return x - y;
    }
}

It gives you max. IntelliSense-support while suggesting mainly valid input, but still fails when used inappropriately. All that using only one, clean, readable and therefore maintainable class.

The only thing thats kinda ugly about this, is the huge generic Type-Constraint, but this is what all numeric types in C# have in common so its better to do it that way.

like image 109
nozzleman Avatar answered Jan 17 '23 15:01

nozzleman