0

This is probably an old problem in a new bottle. But, I never encountered this myself before.

I am developing a statistics library in .net. I have developed a Set<T> data structure. Now, I want to derive a data structure named DescriptiveStatisticalSet<T>, and I want this set to be able to operate only on integer and double types.

Say, I have the following interfaces and classes:

public interface IIntegerDataType  
{
    int Data { get; set; }
    int Add(int other);
}

public interface IDoubleDataType  
{
    double Data { get; set; }
    double Add(double other);
}
public class IntegerDataType : IIntegerDataType
{
    public int Data { get; set; }

    public int Add(int other)
    {
        return Data + other;
    }
}
public class DoubleDataType : IDoubleDataType
{
    public double Data { get; set; }

    public double Add(double other)
    {
        return Data + other;
    }
}

Is it possible to create a generic type DataType<T> so that both (and only) IntegerDataType and DoubleDataType could be accessed through that generic type?

EDIT

I have devised the following solution:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataTypeNamespace
{
    public interface IDataType
    {
        object Add(object other); 
        void SetVal(object other);
    }
    public interface IDataType<T> where T : IDataType, new()
    {
        T Add(T other);
    }
    class IntegerDataType : IDataType
    {
        public int Data { get; set; }

        public object Add(object other)
        {
            int o = ((IntegerDataType)other).Data;
            return Data + o;
        }
        public void SetVal(object other)
        {
            Data = (int)other;
        }
    }

    class DoubleDataType : IDataType
    {
        public double Data { get; set; }

        public object Add(object other)
        {
            double o = ((DoubleDataType)other).Data;
            return Data + o;
        }

        public void SetVal(object other)
        {
            Data = (double)other;
        }
    }

    public class DataType<T> : IDataType<T> where T : IDataType, new()//https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-constraint
    {
        IDataType _item;
        public DataType(IDataType item)
        {
            _item = item;
        }

        public T Add(T other)
        {
            object o = _item.Add(other);

            T t = new T();

            t.SetVal(o);

            return t;
        }
    }

    public class MainClass
    {
        public static void Main(string[] args)
        {
            //IntegerDataType item1 = new IntegerDataType();
            //item1.Data = 10;

            //IntegerDataType item2 = new IntegerDataType();
            //item2.Data = 20;

            //DataType<IntegerDataType> l1 = new DataType<IntegerDataType>(item1);
            //IntegerDataType sum1 = l1.Add(item2);

            DoubleDataType item3 = new DoubleDataType();
            item3.Data = 10.5;

            DoubleDataType item4 = new DoubleDataType();
            item4.Data = 20.5;

            DataType<DoubleDataType> l2 = new DataType<DoubleDataType>(item3);
            DoubleDataType sum2 = l2.Add(item4);
        }
    }
}

Can someone review this?

Or, maybe help me to improve?

user366312
  • 16,949
  • 65
  • 235
  • 452
  • 1
    So you only want `DataType` and `DataType`? Why would you want that? Sounds like an XY problem to be honest... – Sweeper Jun 22 '20 at 01:41
  • 3
    People [keep trying to do this](https://jonskeet.uk/csharp/genericoperators.html) and always get killed by the fact that `double`s have out-of-band values like `NaN` and `Inf`. There was [an article](https://www.codeproject.com/Articles/8531/Using-generics-for-calculations) that proposed some solutions but, IMHO, the added complexity is not worth it; Interfaces should reduce the number of moving parts of your API, not increase them. – Dour High Arch Jun 22 '20 at 01:41
  • @Sweeper at least what OP is asking is very doable... Knowing answer will unlikely help them as it indeed sounds like XY problem - but maybe solution to X would help them... – Alexei Levenkov Jun 22 '20 at 02:27
  • What is the target usage of such data structure? If you want to limit the data type to be passed to a method to be integer or double, you can create method with parameters integer and double types. – Chetan Jun 22 '20 at 04:21
  • @ChetanRanpariya, to limit type to just a choice between several A or B types. – user366312 Jun 22 '20 at 04:32
  • 1
    If `A` or `B` types are some class, interface or struct type you can use Generic Constraint such as `where T : class` or `where T : ` or `where T : struct`. C# does not support generic constraint for specific value types such as int, double, float etc. You can read more [here](https://stackoverflow.com/questions/32664/is-there-a-constraint-that-restricts-my-generic-method-to-numeric-types). – Chetan Jun 22 '20 at 04:43
  • @ChetanRanpariya, Check [this](https://dotnetfiddle.net/qJGsAK). Can you comment on this? – user366312 Jun 22 '20 at 04:50
  • Yes.. that's one way to do it. but interface `IDataType` is still open to be used to create class for other data types such `float`, `DateTime` etc. It does not restrict to `int` and `double`. When I said Constraint for specific Value types are not supported, I meant we can not do `T : int` or `T : double`. – Chetan Jun 22 '20 at 04:59
  • @ChetanRanpariya, *but interface IDataType is still open to be used to create class for other data types such float, DateTime etc.* --- this is not the issue as the target is to restrict immediate access. Can you improve the code? If Yes, you can post an answer here. :) – user366312 Jun 22 '20 at 05:01
  • @user366312 not sure if this is as per your expectation, but I could think of simpler solution as [here](https://dotnetfiddle.net/xI7V6b). – Chetan Jun 22 '20 at 05:25

1 Answers1

1

Am I missing something...Its unclear why you are not just using the type at the top level such as:

public interface Both<T>
{
    T Data { get; set; }
    T Add(T value);
}

...

public class MyInt : Both<int>
{
    public int Data { ... }

    public int Add(int value)
    {
        ...;
    }
}


public class MyDouble: Both<double> ...
 
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122