# Wednesday, 23 January 2008
« IKVM 0.36 Update 1 Release Candidate 1 | Main | IKVM 0.36 Update 1 Release Candidate 2 »
How To Get an Explicit Interface Implementation Method

Suppose you have a Type that you know implements IEnumerable, how do you get the GetEnumerator method?

Both the developer(s) at Microsoft and the Mono developer(s) that wrote System.Xml.Serialization managed to find the same wrong answer to this question. Here's the code from Mono, but Microsoft does somethig very similar:

MethodInfo met = type.GetMethod ("GetEnumerator", Type.EmptyTypes);
if (met == null) {
  // get private implemenation
  met = type.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
                        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                        null, Type.EmptyTypes, null);

The reason this is wrong is that the name of the private method is an implementation detail of the compiler that was used to compile the code. C# happens to name the private method this way, but other languages may not.

For example, try the following VB webservice:

<%@ WebService Language="VB" Class="Service1" %>

Imports System.Collections
Imports System.Web.Services

Public Class Service1
  Inherits WebService

  <WebMethod()> Public Function HelloWorld() As Frob
    Return New Frob()
  End Function
End Class

Public Class Frob
  Implements IEnumerable

  ' Note that this method is private
  Private Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
    Return "frob".GetEnumerator()
  End Function

  Public Sub Add(ByVal obj As Object)
    Throw New NotSupportedException()
  End Sub
End Class

If you run this webservice on .NET, you'll an exception inside System.Xml.Serialization.TypeScope.GetTypeDesc(), because it expects to find a public GetEnumerator method or a private System.Collections.IEnumerable.GetEnumerator method. However, VB allows you to pick the method name (in this case simply GetEnumerator). If you make the GetEnumerator method public, the webservice will work.

The Right Way

Here's the right way to get the method:

MethodInfo getEnumerator = typeof(IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
InterfaceMapping map = type.GetInterfaceMap(typeof(IEnumerable));
int index = Array.IndexOf(map.InterfaceMethods, getEnumerator);
MethodInfo meth = map.TargetMethods[index];

Meta Question

Of course, the real question remains unanswered. Why do we need the MethodInfo in the first place? Wouldn't Xml serialization be better off by simply using the IEnumerable interface?

Wednesday, 23 January 2008 07:37:35 (W. Europe Standard Time, UTC+01:00)  #    Comments [8]