RuntimeHelpers.IsReferenceOrContainsReferences<T>() returns a boolean indicating whether T is a reference type or contains a reference type. One practical use case is micro-optimizing collections when removing items: if T is a reference type, you must clear the slot to allow the GC to collect the item; if T is a value type, this step is unnecessary, saving a memory write. While a small optimization, it can add up in tight loops. The JIT replaces the call with a constant and eliminates dead branches at runtime.
Here is an example of a custom list that uses this method:
C#
class CustomList<T>
{
private readonly T[] _items;
private int _count;
public CustomList(int capacity)
=> _items = new T[capacity];
public void Push(T item)
{
if (_count == _items.Length)
throw new InvalidOperationException("The list is full.");
_items[_count] = item;
_count++;
}
public T Pop()
{
if (_count == 0)
throw new InvalidOperationException("The list is empty.");
var value = _items[_count - 1];
// If T is a reference type or contains a reference type, you need to remove
// the reference to the item to allow the GC to collect it.
// For instance, CustomList<string> will need to do that, but CustomList<int> won't.
// Note: The JIT will remove the if statement if the condition is false, so there is no performance impact.
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
_items[count - 1] = default;
}
_count--;
return value;
}
}
Do you have a question or a suggestion about this post? Contact me!