IronPython: Accessing the .NET Field

The .NET libraries normally do not expose the public field, but we can still find its' presence for certain scenarios. IronPython treats the .NET fields like python attribute. For python attribute, the typical operations are set, get and delete. In general, IronPython throws TypeError when deleting members of CLR types and their objects (so for fields). To do set and get operation, the IronPython code looks similar to C# code. Updating (setting) values to the read-only or literal fields throws as we expect.

public class C {
    public static int StaticField;
    public int InstanceField;
}

>>> ...
>>> C.StaticField = 1          # set
>>> C.StaticField              # get
1
>>> c = C()
>>> c.InstanceField = 2        # set
>>> c.InstanceField            # get
2

Guess what you will get for C.InstanceField? It is "field descriptor", same as C.__dict__['InstanceField'], upon which we can call __set__/__get__ or two equivalent helper methods SetValue/GetValue (feel like repeating CLR reflection FieldInfo API here). Although not shown below, we can also set/get the value of the static field too by calling these methods on C.__dict__['StaticField'].

>>> C.InstanceField
<field# InstanceField on C>
>>> C.InstanceField is C.__dict__['InstanceField']
True
>>> C.InstanceField.__set__(c, 3)
>>> C.InstanceField.__get__(c)
3
>>> C.InstanceField.SetValue(c, 4)
>>> C.InstanceField.GetValue(c)
4

IronPython allows accessing static field on instance too. On the other hand, C# compiler requires type name to access static member (otherwise CS0176).

>>> c.StaticField = 5
>>> c.StaticField, C.StaticField
(5, 5)

Updating fields of value types is not allowed. If interested, you may go ahead read the design decision here. Until recently I did not know that as a remedy, the feature of setting fields/properties in the constructor call should be able to set field for value types while still keeping value types effectively immutable after the creation. Unfortunately we had no tests to cover this part (which never worked). This code below illustrates the expected behavior. I expect it to work soon.

public struct MyPoint {
    public int X, Y;
    public override string ToString() { return string.Format("X: {0}, Y: {1}", X, Y); }
}

>>> p = MyPoint(X=1, Y=2)
>>> p
<MyPoint object at 0x000000000000002C [X: 1, Y: 2]>
>>> p.X = 3
# one kind of exception still throws