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?
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
{
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With