C
C#4mo ago
teadrinker

Avoiding boxing (causing many small allocations) in generic classes

Can the compiler or runtime optimization avoid trivial boxing like (T)(object)? Example below (simplified, real case would have more types and more functionality which makes non-generic solution cause a lot of code duplication)
interface IValueWrap
{
void SetFloatValue(float v);
void SetValue(object v);
}
public class ValueWrap<T> : IValueWrap
{
public T val;
public void SetValue(object v)
{
val = (T)System.Convert.ChangeType(v, typeof(T));
}
public void SetFloatValue(float v)
{
// val = val switch
// {
// float f => v, // Error: Cannot implicitly convert type 'float' to 'T'
// _ => (T) System.Convert.ChangeType(v, typeof(T))
// };

// switch (val)
// {
// case float floatVal: val = v; break; // Error: Cannot implicitly convert type 'float' to 'T'
// default: SetValue(val); break;
// }

if (typeof(T) == typeof(float))
{
// val = v; // Error: Cannot implicitly convert type 'float' to 'T'
// val = (T) v; // Error: Cannot convert type 'float' to 'T'
// Set(v); // Error: ... There is no boxing conversion from 'float' to 'T'
val = (T)(object)v; // Works, but how can I avoid boxing/unboxing to object?
}
else
SetValue(v);
}
public void Set<T2>(T2 v) where T2 : T
{
val = v;
}
}
interface IValueWrap
{
void SetFloatValue(float v);
void SetValue(object v);
}
public class ValueWrap<T> : IValueWrap
{
public T val;
public void SetValue(object v)
{
val = (T)System.Convert.ChangeType(v, typeof(T));
}
public void SetFloatValue(float v)
{
// val = val switch
// {
// float f => v, // Error: Cannot implicitly convert type 'float' to 'T'
// _ => (T) System.Convert.ChangeType(v, typeof(T))
// };

// switch (val)
// {
// case float floatVal: val = v; break; // Error: Cannot implicitly convert type 'float' to 'T'
// default: SetValue(val); break;
// }

if (typeof(T) == typeof(float))
{
// val = v; // Error: Cannot implicitly convert type 'float' to 'T'
// val = (T) v; // Error: Cannot convert type 'float' to 'T'
// Set(v); // Error: ... There is no boxing conversion from 'float' to 'T'
val = (T)(object)v; // Works, but how can I avoid boxing/unboxing to object?
}
else
SetValue(v);
}
public void Set<T2>(T2 v) where T2 : T
{
val = v;
}
}
3 Replies
reflectronic
reflectronic4mo ago
yes, the optimizer will remove the boxing from (T)(object)f
teadrinker
teadrinker4mo ago
At compile time or run-time/JIT?
reflectronic
reflectronic4mo ago
the JIT is able to remove it