Use IronPython to Experiment .NET Libraries

When working on .NET projects, we often need to find the right API or the proper parameters to pass in to a particular method. Usually we search MSDN or turn to other search engines to solve such issue. Some people, however, prefer first-hand experience over search; they perfer experimenting or playing with a small piece of C# or VB.Net code. These people probably should consider using IronPython, which I found can save a lot of edit-save-compile-run cycles.

For example, suppose I want to make sure I understand the functionality of Path.GetTempFileName and Path.GetRandomName before using either API in my code. This is how I would do in IronPython:

D:\IronPython > IronPythonConsole.exe
>>> import System
>>> from System.IO import *
>>> Path.GetTempFileName()
'C:\\Documents and Settings\\username\\Local Settings\\Temp\\tmpEE7.tmp'
>>> Path.GetRandomFileName()
'fbrhamew.f13'

We see the instant functionality result with 4 lines of python code. No Ctrl+S, No csc.exe or vbc.exe... Another example: the tricky method String.Format(string, object). Sometimes we need to tweak the formatting string, rebuild the entire solution several times to get the expected string. Let us try to format a long number to 8-char hex. After trying a few different things based on my vague memory, finally I get what I want.

>>> from System import *
>>> String.Format("{0,8:X}", 12345678)
' BC614E'
>>> String.Format("{0,X8}", 12345678)
Traceback (most recent call last):
File , line 0, in input##37
File , line 0, in Format
File , line 0, in AppendFormat
File , line 0, in FormatError
SystemError: Input string was not in a correct format.
>>> String.Format("{0:X8}", 12345678)
'00BC614E'

Don't like typing? IronPythonConsole keeps the history, so we can use up/down key to get our previous codes back, and then do a little more editing. Or we can save the method object first, and easily have more String.Format fun (yeah...next time you want to play with code snippets when reading blogs, try doing so with IronPython...)

>>> f = String.Format
>>> f("{0:X8}", 12345678)
'00BC614E'
>>> f("{{0:X8}}", 12345678)
'{0:X8}'
>>> f("{{{0:X8}}}", 12345678)
'{X8}'

Just another FYI: 1.0 Beta1 also shipped a winform version console: IronPythonWindowConsole.exe, which provides similar typing experience like VS IDE intellisense.

Let me finish this post with an experiment with System.Reflection.BindingFlags (seems this is really confusing). I will try with the type of System.Random; Reflector shows this type as follows (I will only focus on these 8 methods):

 [Serializable, ComVisible(true)]
public class Random
{
      // Methods
      public Random();
      public Random(int Seed);
      private double GetSampleForLargeRange();
      private int InternalSample();
      public virtual int Next();
      public virtual int Next(int maxValue);
      public virtual int Next(int minValue, int maxValue);
      public virtual void NextBytes(byte[] buffer);
      public virtual double NextDouble();
      protected virtual double Sample();

      // Fields
      ......
} 

>>> import System
>>> from System import *
>>> from System.Reflection import *
>>> r = Random( )
>>> t = r.GetType()
>>> gm = t.GetMethods
>>> gm()
System.Reflection.MethodInfo[](Int32 Next(), Int32 Next(Int32, Int32), Int32 Next(Int32), Double NextDouble(), Void NextBytes(Byte[]), System.Type GetType(), System.String ToString(), Boolean Equals(System.Object), Int32 GetHashCode())
>>> _.Length
9
        It also includes 4 public methods defined in System.Object; and no private/protected methods
>>> bf = BindingFlags
>>> gm(bf.Public)
System.Reflection.MethodInfo[]()
        Nothing returned if only specifying Public, need another flag?
>>> gm(bf.Public | bf.Static)
System.Reflection.MethodInfo[]()
        This can not tell much, since Random does not have static methods.
>>> gm(bf.Public | bf.Instance)
System.Reflection.MethodInfo[](Int32 Next(), Int32 Next(Int32, Int32), Int32 Next(Int32), Double NextDouble(), Void NextBytes(Byte[]), System.Type GetType(), System.String ToString(), Boolean Equals(System.Object), Int32 GetHashCode())
        Looks same as gm() returned? Actually gm() returns static methods too, but for this example, Random does not have any.
>>> gm(bf.Public | bf.Instance | bf.DeclaredOnly)
System.Reflection.MethodInfo[](Int32 Next(), Int32 Next(Int32, Int32), Int32 Next(Int32), Double NextDouble(), Void NextBytes(Byte[]))
        DeclaredOnly will not return the 4 methods defined in System.Object
>>> gm(bf.NonPublic | bf.Instance)
System.Reflection.MethodInfo[](Double Sample(), Int32 InternalSample(), Double GetSampleForLargeRange(), System.Object MemberwiseClone(), Void Finalize())
>>> _.Length
5
        Get back protected method Sample() here, and another 2 private methods defined in Sample; also 2 methods from System.Object
>>> gm(bf.Public | bf.NonPublic | bf.Instance)
System.Reflection.MethodInfo[](Double Sample(), Int32 InternalSample(), Int32 Next(), Double GetSampleForLargeRange(), Int32 Next(Int32, Int32), Int32 Next(Int32), Double NextDouble(), Void NextBytes(Byte[]), System.Type GetType(), System.Object MemberwiseClone(), System.String ToString(), Boolean Equals(System.Object), Int32 GetHashCode(), Void Finalize())
>>> _.Length
14
        We got back all 14(5+9) instance methods from type Object and Random, public, protected or private
>>> ...