imaginar el siguiente código simple:Cómo convertir un valor de tipo genérico T a double sin boxeo?
public void F<T>(IList<T> values) where T : struct
{
foreach (T value in values)
{
double result;
if (TryConvertToDouble((object)value, out result))
{
ConsumeValue(result);
}
}
}
public void ConsumeValue(double value)
{
}
El problema con el código anterior está lanzando a oponerse, lo que resulta en el boxeo en el bucle.
¿Hay alguna manera de lograr la misma funcionalidad, es decir, alimentar a ConsumeValue con todos los valores sin recurrir al boxeo en el bucle foreach? Tenga en cuenta que F debe ser un método genérico.
Puedo vivir con un código de preparación costoso, siempre que se ejecute fuera del circuito una sola vez. Por ejemplo, si se necesita emitir un método dinámico sofisticado, está bien si se hace solo una vez.
EDITAR
T se garantiza que sea de algún tipo numérico o bool.
Motivación. Imagine una aplicación impulsada por metadatos, donde un agente informa un flujo de datos, donde el tipo de elemento de datos se emite dinámicamente en base a los metadatos del flujo de datos. Imagine también que hay un motor normalizador que sabe normalizar las secuencias de datos numéricos de acuerdo con algún algoritmo. El tipo de flujo de datos numéricos entrantes se conoce solo en tiempo de ejecución y se puede dirigir a un método genérico de ese tipo de datos. El normalizador, sin embargo, espera dobles y produce dobles. Esta es una descripción de muy alto nivel, por favor no profundizar en ella.
Edit2
En cuanto al reparto de duplicar. En realidad tenemos un método para convertir al doble con la firma siguiente:
bool TryConvertToDouble(object value, out double result);
Debería haber usado en el ejemplo, en primer lugar, pero queríamos ahorrar espacio y algo escrito que no se va a trabajar. Solucionado ahora Gracias por anotar
Edit3
Guys, la implementación actual hace caja los valores. E incluso si no tengo el veredicto del perfilador en cuanto a la penalización del rendimiento (si corresponde), aún así, me interesa saber si hay una solución sin boxeo (y sin convertirla en cadena). Déjame llamarlo interés puramente académico. Esto realmente me interesa, porque cosas así son triviales en C++ con plantillas, pero, por supuesto, no estoy empezando otro argumento estúpido e inútil sobre qué es mejor .NET genéricos o plantillas de C++. Por favor, ignora esta última oración.
EDIT4
Gracias a https://stackoverflow.com/users/267/lasse-v-karlsen que proporcionó la respuesta. En realidad, he utilizado el ejemplo de código para escribir una clase simple como esto:
public static class Utils<T>
{
private static class ToDoubleConverterHolder
{
internal static Func<T, double> Value = EmitConverter();
private static Func<T, double> EmitConverter()
{
ThrowIfNotConvertableToDouble(typeof(T));
var method = new DynamicMethod(string.Empty, typeof(double), TypeArray<T>.Value);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
if (typeof(T) != typeof(double))
{
il.Emit(OpCodes.Conv_R8);
}
il.Emit(OpCodes.Ret);
return (Func<T, double>)method.CreateDelegate(typeof(Func<T, double>));
}
}
public static double ConvertToDouble(T value)
{
return ToDoubleConverterHolder.Value(value);
}
}
Dónde:
- ThrowIfNotConvertableToDouble (Tipo) es un método simple que hace que el tipo dado puede ser convertido a duplicar , es decir, algún tipo numérico o bool.
- TypeArray es una clase de ayuda para producir
new[]{ typeof(T) }
El método Utils.ConvertToDouble convierte cualquier valor numérico que se duplique en la forma más eficiente, lo demuestra la respuesta a esta pregunta.
Funciona como un encanto - gracias hombre.
El problema con lo anterior es también que no tiene mucho sentido. ¿Por qué usar un método genérico, con una restricción, y luego convertirlo en un doble? ¿Puedes explicar más claramente lo que estás tratando de lograr? –
Esto me parece extraño. ¿Por qué estás lanzando una estructura genérica a un objeto y luego a un doble? ¿Hay algún problema con este ejemplo? ¿Necesitamos más contexto? Este código parece tan fuera de lugar, que no sé cómo responderlo ... –
He actualizado la pregunta. – mark