代码改变世界

REFLECTION ON A METHOD WITH AN OUT PARAMETER

2012-03-11 17:17  mleader1  阅读(172)  评论(0编辑  收藏  举报

如何通过Reflection来运行带out参数的方法


As I code my commercial Dynamic Data libraries for ASP.NET 4 support, I’ve elected to deliver one assembly compiled under .net 3.5 SP 1 that also supports new features of ASP.NET 4. 3.5SP1 is the initial release of Dynamic Data. To interact with the new properties and methods in ASP.NET 4, I am using .net Reflection.

I have long used .net reflection, so I didn’t think there were many more things to learn. Today I encountered a new case, a method that has an out parameter.

Here’s the method I wanted to call. It's on the class System.Web.DynamicData.DynamicDataExtensions:

public static bool TryGetMetaTable(this INamingContainer control, out MetaTable table);
To call a function using .reflection, you take these actions:
  1. Call a GetMethod(“methodname”) method on the specific type.
  2. Call the Invoke method on the MethodInfo object that was returned by GetMethod.

If this function did not have an out parameter, the code would look like this:

Type[] vTypes = new Type[] { typeof(INamingContainer), typeof(MetaTable) };
MethodInfo vTGMTMI = typeof(DynamicDataExtensions).GetMethod("TryGetMetaTable", BindingFlags.Public | BindingFlags.Static,  
   null,  vTypes, null);
if (vTGMTMI == null)
   throw new NotImplementedException("Must use ASP.NET 4.0 or higher.");

object[] vParms = new object[] { GridView, null };
bool vResult = (bool) vTGMTMI.Invoke(null, BindingFlags.InvokeMethod, null, vParms, null);
if (vResult)
  // metatable returned is in vParms[1]

The GetMethod() method gets more complex with that out parameter. You must pass the output parameter TYPE as a reference to the intended type.
 
Approach 1 - Using Type.MakeByRefType
As pointed out in the comments, the Type class has the tools needed.  Use the method MakeByRefType() like this:
Type[] vTypes = new Type[] { typeof(INamingContainer), typeof(MetaTable).MakeByRefType() };
 
Approach 2 - Using GetType("string") 
Before learning of the MakeByRefType() method, I used this technique. I wanted to keep it in the post because I educates on how to use GetType("string") for an out parameter. 

Pass the fully qualified type name into the Type.GetType(“string of the type”) method. The type within the string must be:
  • full name
  • end with “&” to indicate its a pointer

Here is the MetaTable class as a full qualified name, including type, &, and assembly name:

Type.GetType("System.Web.DynamicData.MetaTable&, System.Web.DynamicData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")

Here’s the corrected code, allowing the MetaTable's type supply both full names.

Type vMetaTableP = Type.GetType(typeof(MetaTable).FullName + "&," + typeof(MetaTable).Assembly.FullName);
Type[] vTypes = new Type[] { typeof(INamingContainer), vMetaTableP };


The big trick is to avoid using typeof(MetaTable).AssemblyQualifiedName, because it omits the “&”.

Putting it all together 

This is the complete code using my preferred solution, MakeByRefType().
Type[] vTypes = new Type[] { typeof(INamingContainer), typeof(MetaTable).MakeByRefType() };

MethodInfo vTGMTMI = typeof(DynamicDataExtensions).GetMethod("TryGetMetaTable", BindingFlags.Public | BindingFlags.Static,  
   null,  vTypes, null);
if (vTGMTMI == null)
   throw new NotImplementedException("Must use ASP.NET 4.0 or higher.");

object[] vParms = new object[] { GridView, null };
bool vResult = (bool) vTGMTMI.Invoke(null, BindingFlags.InvokeMethod, null, vParms, null);
if (vResult)
  // metatable returned is in vParms[1]

Note that the GetMethod takes a parameter of type ParameterModifier. It certainly is involved with out parameters, but only when calling COM functions. In this case, the last parameter for GetMethod is null instead of a ParameterModifier array.