0

I have a class which is defined in the following manner. The interface and concrete type both have a Type Parameter which I expect to be a double, int, decimal or DateTime. I've added a where constraint of IComparable however this class does some heavy numeric lifting so I want to avoid boxing and unboxing. The class definitions are as follows:

public interface INumericClass<T1, T2>  where T1:IComparable 
    where T2:IComparable
{
    void DoLongNumericOperation();
}  

public class NumericClass<T1, T2> : INumericClass<T1, T2> where T1:IComparable 
    where T2:IComparable 
{     
    private IList _innerArray1 = new T1[1000000];
    private IList _innerArray2 = new T2[1000000];      
    public void DoLongNumericOperation()     
    {         
        for(int i = 0; i < _innerArray1.Count; i++)         
        {             
            // some computation goes on in here             
            // for example, it could be             
            double aConstant = 123.45;
            double aScalar = 56.7;
            _innerArray1[i] = (Convert.ToDouble(_innerArray1[i]) * aConstant + aScalar);
            _innerArray2[i] = (Convert.ToDouble(_innerArray2[i]) * aConstant + aScalar);         
        }     
    } 
} 

These classes would be declared and used in calling code something like as follows

var numeric = new NumericClass<int, double>();
numeric.DoLongNumericComputation(); 

Now internally the way I handle the multiple types is to cast T to double. However I am concerned that since I have specified that T is a type param of type IComparable that unboxing/boxing is going on. In addition DateTime provides an additional overhead. What I am doing in the case of this type is converting the .Ticks property to a double and operating on that.

I welcome any information on what is going on under the hood in the CLR, plus suggestions to improve performance such as API changes to strongly type each of the numeric operations to improve performance and memory usage.

Edit: I should also add the above implementation is sub-optimum as if you declare NumericClass it starts throwing on the cast from Tx to double. I can only assume its casting through IComparable although Im not sure.

Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178

2 Answers2

2

Without seeing a more complete example, here is what I can recommend.

public interface IConvertToDouble<T>
   where T : IComparable
{
    double Convert(T input);
    T ConvertBack(double input);
}

public class NumericClass<T, U>
    where T : IComparable,
          U : IComparable
{
    private IConvertToDouble<T> _tConverter;
    private IConvertToDouble<U> _uConverter;
    private List<T> _internalTs;
    private List<U> _internalUs;

    public NumericClass(IConvertToDouble<T> tConverter, IConvertToDouble<U> uConverter)
    {
        _tConverter = tConverter;
        _uConverter = uConverter;
        _internalTs = new List<T>();
        _internalUs = new List<U>();
    }

    public void DoLongNumericOperation()
    {
        for(int i = 0; i < innerArray.Length; i++)
        {
            // some computation goes on in here
            // for example, it could be
            double aConstant = 123.45;  
            double aScalar = 56.7
            _internalTs[i] = _tConverter.ConvertBack(_tConverter.Convert(_internalTs[anIndex]) * aConstant + aScalar);
            _internalUs[i] = _uConverter.ConvertBack(_uConverter.Convert(_internalUs[anIndex]) * aConstant + aScalar);
        }
    }
}

Now you don't need to cast your generic objects or have type specific logic in NumericClass.

cadrell0
  • 17,109
  • 5
  • 51
  • 69
  • Hello cadrell0, funnily enough that's exactly what I've done. No casting is involved and I have a type-agnostic "Converter" class. What I'm concerned about however is the boxing/unboxing through object in such an approach. Do you have any light to shed on this? – Dr. Andrew Burnett-Thompson Feb 29 '12 at 14:42
  • My IConvertToDouble interface is not type agnostic. It requires an implementation per type. This is to avoid the boxing / unboxing. – cadrell0 Feb 29 '12 at 14:49
  • 1
    Regardless, isn't worrying about boxing/unboxing a micro optimization? – jrummell Feb 29 '12 at 14:51
  • @jrummell - maybe, but I'm operating on some pretty large datasets. 1m-10m elements and multiple times per second. – Dr. Andrew Burnett-Thompson Feb 29 '12 at 14:55
  • @cadrell0 ahh good idea. Let me look at the codebase and see if I could use this. Ideally I would move the numeric code into strongly typed classes like this to avoid casting through object/IComparable – Dr. Andrew Burnett-Thompson Feb 29 '12 at 14:56
1

See Generic operators.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288