void GenerateCode(Type type) { if (type.IsGenericType && !type.IsGenericTypeDefinition) return; // generate nothing. var implprops = new List<PropertyInfo> (); var miscprops = new List<PropertyInfo> (); foreach (var p in type.GetProperties (BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { if (targets.Contains (p.PropertyType) && !p.PropertyType.IsEnum) implprops.Add (p); else miscprops.Add (p); } output.WriteLine ("// generic ordinal type for " + type); string template = @" public {10}partial class {0} : {1} {2} {{ {7} impl; // constructor, if not abstract. {9} // impl-to-wrapper constructor internal protected {8} ({7} impl) {6} {{ this.impl = impl; {11} Initialize (); }} // initializer void Initialize () {{ // repeat for all auto (new-Android-type) properties {3} }} // explicit conversion operator public static explicit operator {7} ({0} source) {{ return source.impl; }} // For a property whose type is wrapper for Android type, just make it auto property (use private set for get-only ones) {4} // Non-Android properties follow. {5} }} "; var actx = android_ass.GetType ("Android.Content.Context"); var aaset = android_ass.GetType ("Android.Util.IAttributeSet"); // somehow GetConstructor() returns weird results, so this workarounds that. string args = type.GetConstructors ().Any (c => c.GetParameters ().Length == 1 && c.GetParameters () [0].ParameterType.FullName == actx.FullName) ? "XamlView.CurrentContext" : type.GetConstructors ().Any (c => c.GetParameters ().Length == 2 && c.GetParameters () [0].ParameterType.FullName == actx.FullName && c.GetParameters () [1].ParameterType.FullName == aaset.FullName) ? "XamlView.CurrentContext, null" : ""; //if (type.Name == "SlidingDrawer") foreach (var ccc in type.GetConstructors ()) Console.WriteLine ("!!!! " + ccc + " / " + type.GetConstructor (new Type [] {actx}).GetParameters ().Length); string publicConstructor = type.IsAbstract ? String.Empty : String.Format (@" public {0} () : this (new {1} ({2})) {{ }}", type.NonGenericName (), type.CSFullName (), args); string templateInit = @" if (impl.{0} != null) {0} = Extensions.GetWrappedItem<{1}> (impl.{0});"; var isw = new StringWriter () { NewLine = "\n" }; foreach (var p in implprops) if (!p.IsAbstract ()) isw.WriteLine (templateInit, p.Name, p.PropertyType.CSName ()); string templateImplProp = @" public {3}{0} {1} {{ get; {2}set; }}"; var dpsw = new StringWriter () { NewLine = "\n" }; foreach (var p in implprops) dpsw.WriteLine (templateImplProp, p.PropertyType.CSSwitchName (), p.Name, p.IsSetterPublic () ? null : "internal ", GetModifier (p)); string templateOrdProp1 = @" public {3}{0} {1} {{ get {{ return {4}; }} {2} }}"; string templateOrdProp2 = @" public {3}{0} {1} {{ get; {5} }}"; var nsw = new StringWriter () { NewLine = "\n" }; foreach (var p in miscprops) { var setter = String.Format ("set {{ impl.{0} = value; }}", p.Name); nsw.WriteLine (p.IsAbstract () ? templateOrdProp2 : templateOrdProp1, p.PropertyType.CSSwitchName (), p.Name, p.IsSetterPublic () ? setter : null, GetModifier (p), GetValueExpression (p), p.IsSetterPublic () ? "set;" : null); } string gconsts = null; foreach (var arg in type.GetGenericArguments ()) { var gca = String.Join (",", (from t in arg.GetGenericParameterConstraints () select t.CSSwitchName ()).ToArray ()); gconsts += String.IsNullOrEmpty (gca) ? null : "where " + arg.Name + " : " + gca; } // FIXME: write custom attributes bool callBase = targets.Contains (type.BaseType); output.WriteLine (template, type.CSName (), type.BaseType.CSSwitchName (), gconsts, isw, dpsw, nsw, callBase ? " : base (impl)" : null, type.CSFullName (), type.NonGenericName (), publicConstructor, type.IsAbstract ? "abstract " : null, callBase ? null : "XamlView.Register (impl, this);"); }