Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I avoid boxing when pass a struct value as an interface value?

Tags:

c#

Interface (I) is a reference type, struct (S) is a value type. Structs can implement interfaces.

public interface I {}
struct S: I {}

Assume there is a value of S which is passed to a method as an argument of I. In this case it has to be boxed.

void Method(I i) {}

void Test() {
   var s = new S();
   this.Method(s); // <---- boxing!
}

Is there a way to avoid boxing in this case?

like image 242
Trident D'Gao Avatar asked Jul 14 '13 13:07

Trident D'Gao


1 Answers

You can avoid boxing if you change the definition of Method to:

void Method<T>(T i) where T : I
{
}

This avoids boxing, because at runtime the CLR specialises generic methods based on the type of the generic argument(s). Reference types can all share the same implementation, while struct types each get their own version. This means all the operations in Method which depend on T will take into account the size of the concrete struct type.

You must be careful however, since calling virtual methods defined on System.Object like Equals or GetHashCode will cause i to be boxed since virtual method dispatch requires a method table pointer (although the JIT may be able to do the dispatch statically in some cases). However, if your struct type overrides the virtual method(s) in question, then boxing will not need to be done, since the method to call is again known statically since structs (and hence their members) are sealed.

Usually you can avoid calling Equals or GetHashCode directly by constraining T further to implement IEquatable<T> and using an IEqualityComparer<T> for comparisons e.g.

void Method<T>(T i) where T : I, IEquatable<T>
{
    T other = ...
    if(i.Equals(other))    //avoids boxing
    {
    }
}
like image 116
Lee Avatar answered Oct 06 '22 15:10

Lee