2010-03-02 7 views
5

Me gustaría escribir una clase LinearInterpolator, donde X es el tipo del valor del eje X e Y el tipo del valor del eje Y. No puedo ver cómo hacer esto de modo que X podría ser un DateTime o un doble. La clase es algo así como más adelante (que no se ha probado):Un interpolador lineal genérico: cómo lidiar con DateTime?

class LinearInterpolator<X, Y> 
{ 
    private List<X> m_xAxis; 
    private List<Y> m_yAxis; 

    public LinearInterpolator(List<X> x, List<Y> y) 
    { 
     m_xAxis = x; 
     m_yAxis = y; 
    } 

    public Y interpolate(X x) 
    { 
     int i = m_xAxis.BinarySearch(x); 
     if (i >= 0) 
     { 
      return m_yAxis[i]; 
     } 
     else 
     { 
      // Must interpolate. 
      int rightIdx = ~i; 
      if (rightIdx >= m_xAxis.Count) 
       --rightIdx; 
      int leftIdx = rightIdx - 1; 

      X xRight = m_xAxis[rightIdx]; 
      X xLeft = m_xAxis[leftIdx]; 
      Y yRight = m_yAxis[rightIdx]; 
      Y yLeft = m_yAxis[leftIdx]; 

      // This is the expression I'd like to write generically. 
      // I'd also like X to be compilable as a DateTime. 
      Y y = yLeft + ((x - xLeft)/(xRight - xLeft)) * (yRight - yLeft); 
      return y; 
     } 
    } 
} 

}

Sería fácil en C++, pero soy nuevo en C# genéricos por lo que cualquier ayuda sería muy apreciada.

+0

Idealmente, esto funcionaría, pero como 'TimeSpan' no es compatible con' TimeSpan/TimeSpan -> double' o 'TimeSpan * double -> TimeSpan' (por razones que incluso pueden considerarse sensatas) creo que estás fuera en el frio. Puede restar tiempos para obtener intervalos y volver a agregarlos, pero no puede encontrar, por ejemplo, la mitad de un intervalo sin escribir código no genérico. – hobbs

+2

Los genéricos de C++ no son lo mismo que los genéricos de C#. El compilador de C++ especializa las plantillas en tiempo de compilación. C# genera código genérico que está especializado en tiempo de ejecución. Una cosa que no funciona son los operadores, no hay un operador genérico de "agregar" o "dividir". No puede hacer que este código funcione por diseño. –

Respuesta

1

Utilice DateTime.Ticks como valor interpolado. Puede usar un tipo long como su genérico para interpolar entre horas.

+0

Si 'long' no se prefiere, en su lugar puede usar' int' para interpolar intervalos de 0 .. * n * como un desplazamiento de tilde desde una base 'DateTime'. p.ej. 'DateTime.AddTicks (desplazamiento)'. – spoulson

1

Una cosa a saber es que C# no admite la anulación del operador. Entonces, tal código no funciona.

Una solución como Spoulson dijo es no usar genéricos, y usar int o long en lugar de T, y usar DateTime.Ticks.

+1

Más exactamente, no admite el polimorfismo basado en firmas como lo hacen las plantillas C++, por lo que no puede tener una clase genérica sobre tipos aritméticos. –

1

no hay una buena manera de hacer matemáticas de C# genéricos, por lo que tiene que hacer algo como esto:

Y y = FromDouble<Y>(ToDouble(yLeft) + ((ToDouble(x) - ToDouble(xLeft))/
      (ToDouble(xRight) - ToDouble(xLeft))) * 
      (ToDouble(yRight) - ToDouble(yLeft))); 

double ToDouble(object val) 
{ 
    if (val is DateTime) 
     return (double)((DateTime)val).Ticks; 
    else 
     return Convert.ToDouble(val); 
} 

T FromDouble<T>(double val) 
{ 
    if (typeof(T) == typeof(DateTime)) 
     return (T)Convert.ChangeType(new DateTime((long)val), typeof(T)); 
    else 
     return (T)Convert.ChangeType(val, typeof(T)); 
} 

No he probado el código, por lo que considera que pseudo-código.

0

Gracias por el asesoramiento. Estoy cambiando mi enfoque y escribiendo un interpolador que funciona solo para dobles; Quiero que la interpolación sea rápida, así que prefiero no hacer comprobaciones de tipo en el tiempo de ejecución.