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?