Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to cast a value of generic type T to double without boxing?
    text
    copied!<p>Imagine the following simple code:</p> <pre><code>public void F&lt;T&gt;(IList&lt;T&gt; values) where T : struct { foreach (T value in values) { double result; if (TryConvertToDouble((object)value, out result)) { ConsumeValue(result); } } } public void ConsumeValue(double value) { } </code></pre> <p>The problem with the above code is casting to object, which results in boxing in the loop.</p> <p>Is there a way to achieve the same functionality, i.e. feeding ConsumeValue with all the values without resorting to boxing in the foreach loop? Note, that F must be a generic method.</p> <p>I can live with an expensive preparation code as long as it is executed outside the loop just once. For instance, if a fancy dynamic method needs to be emitted, then it is fine if done just once.</p> <p><strong>EDIT</strong></p> <p>T is guaranteed to be of some numeric type or bool.</p> <p>Motivation. Imagine meta data driven application, where an agent reports a data stream, where data item type is dynamically emitted based on the data stream meta data. Imagine also, that there is normalizer engine, which knows to normalize numeric data streams according to some algorithm. The type of the incoming numeric data stream is known only at run time and can be directed to a generic method of that data type. The normalizer, however, expects doubles and produces doubles. This is a very high level description, please do not delve into it.</p> <p><strong>EDIT2</strong></p> <p>Concerning the cast to double. Actually we have a method to convert to double with the following signature:</p> <pre><code>bool TryConvertToDouble(object value, out double result); </code></pre> <p>I should have used it in the example in the first place, but I wanted to save space and written something that is not going to work. Fixed it now. Thanks for noting.</p> <p><strong>EDIT3</strong></p> <p>Guys, the current implementation does box the values. And even if I do not have the profiler's verdict as to performance penalty of it (if any), still I am interesting to know whether there is a solution without boxing (and without converting to string). Let me call it purely academic interest. This really interests me, because things like that are trivial in C++ with templates, but, of course, I am not starting yet another stupid and pointless argument over what is better .NET generics or C++ templates. Please, ignore this last sentence. </p> <p><strong>EDIT4</strong></p> <p>Thanks to <a href="https://stackoverflow.com/users/267/lasse-v-karlsen">https://stackoverflow.com/users/267/lasse-v-karlsen</a> who provided the answer. Actually, I have used his code sample to write a simple class like this:</p> <pre><code>public static class Utils&lt;T&gt; { private static class ToDoubleConverterHolder { internal static Func&lt;T, double&gt; Value = EmitConverter(); private static Func&lt;T, double&gt; EmitConverter() { ThrowIfNotConvertableToDouble(typeof(T)); var method = new DynamicMethod(string.Empty, typeof(double), TypeArray&lt;T&gt;.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&lt;T, double&gt;)method.CreateDelegate(typeof(Func&lt;T, double&gt;)); } } public static double ConvertToDouble(T value) { return ToDoubleConverterHolder.Value(value); } } </code></pre> <p>Where:</p> <ul> <li>ThrowIfNotConvertableToDouble(Type) is a simple method that makes sure the given type can be converted to double, i.e. some numeric type or bool.</li> <li>TypeArray is a helper class to produce <code>new[]{ typeof(T) }</code></li> </ul> <p>The Utils.ConvertToDouble method converts any numeric value to double in the most efficient way, shown by the answer to this question.</p> <p>It works like a charm - thanks man.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload