/// <summary>
/// Python properties may have the following function attributes set to control how they're exposed:
/// - _clr_property_type_ - property type (required)
/// </summary>
/// <param name="propertyName">Property name to add to the type</param>
/// <param name="func">Python property object</param>
/// <param name="typeBuilder">TypeBuilder for the new type the method/property is to be added to</param>
private static void AddPythonProperty(string propertyName, PyObject func, TypeBuilder typeBuilder)
{
// add the method to call back into python
MethodAttributes methodAttribs = MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.ReuseSlot |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName;
using (PyObject pyPropertyType = func.GetAttr("_clr_property_type_"))
{
Type propertyType = pyPropertyType.AsManagedObject(typeof(Type)) as Type;
if (propertyType == null)
{
throw new ArgumentException("_clr_property_type must be a CLR type");
}
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName,
PropertyAttributes.None,
propertyType,
null);
if (func.HasAttr("fget") && func.GetAttr("fget").IsTrue())
{
MethodBuilder methodBuilder = typeBuilder.DefineMethod("get_" + propertyName,
methodAttribs,
propertyType,
null);
ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, propertyName);
il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeGetProperty").MakeGenericMethod(propertyType));
il.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(methodBuilder);
}
if (func.HasAttr("fset") && func.GetAttr("fset").IsTrue())
{
MethodBuilder methodBuilder = typeBuilder.DefineMethod("set_" + propertyName,
methodAttribs,
null,
new Type[] { propertyType });
ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, propertyName);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeSetProperty").MakeGenericMethod(propertyType));
il.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(methodBuilder);
}
}
}