Beispiel #1
0
        public MPObject Encode(IConverterContext ctx, Type type, object obj)
        {
            if (obj == null)
            {
                return(MPObject.Nil);
            }

            var itemType = typeof(object);
            var gt       = Util.GetSubclassOfGenericTypeDefinition(typeof(IList <>), type);

            if (type.IsArray)
            {
                itemType = type.GetElementType();
            }
            else if (gt != null)
            {
                itemType = gt.GenericTypeArguments[0];
            }

            var arr = new List <MPObject>();
            var enm = (IEnumerable)obj;

            foreach (var item in enm)
            {
                arr.Add(ctx.Encode(itemType, item));
            }

            return(new MPObject(MPType.Array, arr));
        }
            public MPObject Encode(IConverterContext ctx, Type type, object obj)
            {
                if (obj == null)
                {
                    return(MPObject.Nil);
                }

                var map   = new Dictionary <MPObject, MPObject>();
                var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                            .Select(p => (prop: p, attr: p.GetCustomAttribute <TFAttributeAttribute>()))
                            .Where(pa => pa.attr != null)
                            .ToArray();

                foreach (var p in props)
                {
                    var name  = p.attr.Name;
                    var value = p.prop.GetValue(obj);

                    var propName  = ctx.Encode(typeof(string), name);
                    var propType  = p.prop.PropertyType;
                    var propValue = (value == null && p.attr.Computed)
                        ? new MPObject(MPType.Ext, UnknownExtension)
                        : ctx.Encode(propType, value);
                    map.Add(propName, propValue);
                }
                return(new MPObject(MPType.Map, map));
            }
Beispiel #3
0
        public MPObject Encode(IConverterContext ctx, Type type, object obj)
        {
            if (obj == null)
            {
                return(MPObject.Nil);
            }

            var map   = new Dictionary <MPObject, MPObject>();
            var props = Resolver.ResolvePropertyNames(type);

            foreach (var prop in props)
            {
                var propInfo = prop.Value;
                if (propInfo.GetIndexParameters()?.Length > 0)
                {
                    // Skip indexer properties
                    continue;
                }

                var propName  = ctx.Encode(typeof(string), prop.Key);
                var propType  = propInfo.PropertyType;
                var propValue = ctx.Encode(propType, propInfo.GetValue(obj));
                map.Add(propName, propValue);
            }
            return(new MPObject(MPType.Map, map));
        }
Beispiel #4
0
        protected virtual T Decode <T>(IConverterContext ctx, MPObject mpo, MPType mpt)
        {
            var t = typeof(T);

            if (mpo.Type == MPType.Nil)
            {
                if (!t.IsValueType)
                {
                    return(default(T));
                }
                if (t.IsGenericType &&
                    t.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    return((T)(object)null);
                }
            }

            if (mpo.Type == mpt)
            {
                return((T)mpo.Value);
            }

            throw new MPConversionException(typeof(T), mpo,
                                            message: $"cannot decode MP type [{mpo.Type}][{mpo.Value}] as intended MP type [{mpt}]");
        }
Beispiel #5
0
        public object Decode(IConverterContext ctx, Type type, MPObject mpo)
        {
            if (mpo.Type == MPType.Nil)
            {
                if (!type.IsValueType)
                {
                    return(null);
                }
                else
                {
                    throw new MPConversionException(type, mpo,
                                                    message: $"cannot return null value for target type [{type.FullName}]");
                }
            }

            if (mpo.Type == MPType.Map)
            {
                var mpoMap = (Dictionary <MPObject, MPObject>)mpo.Value;

                var gt = Util.GetSubclassOfGenericTypeDefinition(typeof(IDictionary <,>), type);
                if (gt != null)
                {
                    var instType = type;
                    var keyType  = gt.GenericTypeArguments[0];
                    var valType  = gt.GenericTypeArguments[1];
                    // If the target type is interface of IDictionary<,>, then
                    // we construct a concrete instance type of Dictionary<,>
                    if (instType.GetGenericTypeDefinition() == typeof(IDictionary <,>))
                    {
                        instType = typeof(IDictionary <,>).MakeGenericType(keyType, valType);
                    }
                    var inst = Activator.CreateInstance(instType);
                    var meth = instType.GetMethod(nameof(IDictionary <object, object> .Add), new[] { keyType, valType });
                    foreach (var kv in mpoMap)
                    {
                        var k = ctx.Decode(keyType, kv.Key);
                        var v = ctx.Decode(valType, kv.Value);
                        meth.Invoke(inst, new[] { k, v });
                    }
                    return(inst);
                }

                if (typeof(IDictionary).IsAssignableFrom(type))
                {
                    var map = type == typeof(IDictionary)
                        ? new Hashtable(mpoMap.Count)
                        : (IDictionary)Activator.CreateInstance(type);
                    foreach (var kv in mpoMap)
                    {
                        var k = ctx.Decode(typeof(object), kv.Key);
                        var v = ctx.Decode(typeof(object), kv.Value);
                        map.Add(k, v);
                    }
                    return(map);
                }
            }

            throw new MPConversionException(type, mpo,
                                            message: $"could not decode [{mpo.Type}] as map object");
        }
Beispiel #6
0
            public object Decode(IConverterContext ctx, Type type, MPObject mpo)
            {
                _log.LogDebug("Decoding Schema Object");
                if (mpo.Type == MPType.Nil)
                {
                    return(null);
                }

                if (mpo.Type == MPType.Map)
                {
                    var map   = (IDictionary <MPObject, MPObject>)mpo.Value;
                    var inst  = Activator.CreateInstance(type);
                    var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                .Select(p => (prop: p, attr: p.GetCustomAttribute <TFAttributeAttribute>()))
                                .Where(pa => pa.attr != null)
                                .ToDictionary(pa => pa.attr.Name, pa => pa);

                    _log.LogDebug($"decoding map of [{map.Count}] values to [{props.Count}] properties on [{type.FullName}]");

                    foreach (var kv in map)
                    {
                        if (kv.Key.Type != MPType.String)
                        {
                            throw new NotSupportedException(
                                      $"got a map key that was not a string: [{kv.Key}]");
                        }

                        var name = (string)ctx.Decode(typeof(string), kv.Key);
                        if (!props.TryGetValue(name, out var pa))
                        {
                            throw new MPConversionException(type, mpo,
                                                            message: $"could not resolve map key to type property [{name}]");
                        }

                        if (kv.Value.Type == MPType.Ext)
                        {
                            var ext = (MPExt)kv.Value.Value;
                            _log.LogDebug($"encountered EXT value [{ext.Type}][{ext.Data.Length}]"
                                          + $" for key [{name}] computed=[{pa.attr.Computed}]");
                            if (pa.attr.Computed && (ext.Type == UnknownValExtTypeCode ||
                                                     ext.Type == UnknownValExtTypeCodeAlt))
                            {
                                _log.LogDebug("    signal for computed property, setting no value");
                                pa.prop.SetValue(inst, null);
                                continue;
                            }
                            _log.LogWarning("unexpected EXT encountered");
                        }

                        var value = ctx.Decode(pa.prop.PropertyType, kv.Value);
                        pa.prop.SetValue(inst, value);
                    }

                    return(inst);
                }

                throw new MPConversionException(type, mpo,
                                                message: $"could not decode [{mpo.Type}] as object");
            }
Beispiel #7
0
        public object Decode(IConverterContext ctx, Type type, MPObject mpo)
        {
            var t = type;

            if (t.IsGenericType &&
                t.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                if (mpo.Type == MPType.Nil)
                {
                    return(null);
                }
                t = type.GenericTypeArguments[0];
            }

            if (t.IsEnum)
            {
                if (mpo.Type == MPType.Integer)
                {
                    return(Enum.ToObject(t, mpo.Value));
                }

                if (mpo.Type == MPType.String)
                {
                    return(Enum.Parse(t, (string)mpo.Value));
                }
            }

            if (t == typeof(Guid))
            {
                if (mpo.Type == MPType.String)
                {
                    return(Guid.Parse((string)mpo.Value));
                }

                if (mpo.Type == MPType.Binary)
                {
                    return(new Guid((byte[])mpo.Value));
                }
            }

            if (t == typeof(DateTime))
            {
                if (mpo.Type == MPType.String)
                {
                    return(DateTime.Parse((string)mpo.Value));
                }
            }

            if (t == typeof(MPExt))
            {
                if (mpo.Type == MPType.Ext)
                {
                    return((MPExt)mpo.Value);
                }
            }

            throw new MPConversionException(type, mpo);
        }
Beispiel #8
0
        public MPObject Encode(IConverterContext ctx, Type type, object obj)
        {
            var t = type;

            if (t.IsGenericType &&
                t.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                if (obj == null)
                {
                    return(MPObject.Nil);
                }
                t = type.GenericTypeArguments[0];
            }

            if (t.IsEnum)
            {
                if (EncodeEnumAsNameString)
                {
                    return(new MPObject(MPType.String, Enum.GetName(t, obj)));
                }
                else
                {
                    return(new MPObject(MPType.Integer, (int)obj));
                }
            }

            if (t == typeof(Guid))
            {
                if (EncodeGuidAsString)
                {
                    return(new MPObject(MPType.String, ((Guid)obj).ToString()));
                }
                else
                {
                    return(new MPObject(MPType.Binary, ((Guid)obj).ToByteArray()));
                }
            }

            if (t == typeof(DateTime))
            {
                return(new MPObject(MPType.String, ((DateTime)obj).ToString("r")));
            }

            if (t == typeof(MPExt))
            {
                return(new MPObject(MPType.Ext, (MPExt)obj));
            }

            throw new MPConversionException(type);
        }
Beispiel #9
0
        public object Decode(IConverterContext ctx, Type type, MPObject mpo)
        {
            switch (mpo.Type)
            {
            case MPType.Array:
                return(ctx.Decode(typeof(ArrayList), mpo));

            case MPType.Map:
                return(ctx.Decode(typeof(Hashtable), mpo));

            default:
                return(mpo.Value);
            }
        }
Beispiel #10
0
        public MPObject Encode(IConverterContext ctx, Type type, object obj)
        {
            Type narrowType = null;

            if (obj == null)
            {
                return(MPObject.Nil);
            }

            if (obj is bool || obj is bool? ||
                obj is byte || obj is byte? ||
                obj is sbyte || obj is sbyte? ||
                obj is short || obj is short? ||
                obj is ushort || obj is ushort? ||
                obj is int || obj is int? ||
                obj is uint || obj is uint? ||
                obj is long || obj is long? ||
                obj is ulong || obj is ulong? ||
                obj is char || obj is char? ||
                obj is float || obj is float? ||
                obj is double || obj is double? ||
                obj is decimal || obj is decimal?||
                obj is byte[] || obj is string
                )
            {
                narrowType = obj.GetType();
            }
            else if (obj is IDictionary ||
                     Util.GetSubclassOfGenericTypeDefinition(
                         typeof(IDictionary <,>), obj.GetType()) != null)
            {
                narrowType = typeof(Hashtable);
            }
            else if (obj is Array || obj is IList ||
                     (Util.GetSubclassOfGenericTypeDefinition(
                          typeof(IList <>), obj.GetType()) != null))
            {
                narrowType = typeof(ArrayList);
            }

            if (narrowType != null)
            {
                return(ctx.Encode(narrowType, obj));
            }

            throw new MPConversionException(type);
        }
Beispiel #11
0
        public MPObject Encode(IConverterContext ctx, Type type, object obj)
        {
            if (obj == null)
            {
                return(MPObject.Nil);
            }

            var                   keyType = typeof(object);
            var                   valType = typeof(object);
            IEnumerable           keys;
            Func <object, object> getter;

            var gt = Util.GetSubclassOfGenericTypeDefinition(typeof(IDictionary <,>), type);

            if (gt != null)
            {
                keyType = gt.GenericTypeArguments[0];
                valType = gt.GenericTypeArguments[1];
                keys    = (IEnumerable)gt.GetProperty("Keys").GetValue(obj);
                var itemProp = gt.GetProperty("Item");
                var index    = new object[] { null };
                getter = k => {
                    index[0] = k;
                    return(itemProp.GetValue(obj, index));
                };
            }
            else
            {
                var d = (IDictionary)obj;
                keys   = d.Keys;
                getter = k => d[k];
            }

            var map = new Dictionary <MPObject, MPObject>();

            foreach (var k in keys)
            {
                var v      = getter(k);
                var mpoKey = ctx.Encode(keyType, k);
                var mpoVal = ctx.Encode(valType, v);
                map.Add(mpoKey, mpoVal);
            }

            return(new MPObject(MPType.Map, map));
        }
Beispiel #12
0
        public override bool TryConvert(IConverterContext <string> context, out List <T> targetValue)
        {
            if (String.IsNullOrEmpty(context.SourceValue))
            {
                targetValue = new List <T>();
                return(true);
            }

            targetValue = new List <T>();

            string[] parts = context.SourceValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string part in parts)
            {
                T item;
                if (context.Repository.TryConvert(part, out item))
                {
                    targetValue.Add(item);
                }
            }

            return(true);
        }
Beispiel #13
0
        public object Decode(IConverterContext ctx, Type type, MPObject mpo)
        {
            if (mpo.Type == MPType.Nil)
            {
                return(null);
            }

            if (mpo.Type == MPType.Map)
            {
                var map   = (IDictionary <MPObject, MPObject>)mpo.Value;
                var inst  = Activator.CreateInstance(type);
                var props = Resolver.ResolvePropertyNames(type);

                foreach (var kv in map)
                {
                    if (kv.Key.Type != MPType.String)
                    {
                        throw new MPConversionException(type, mpo,
                                                        message: "can't resolve property from non-string key");
                    }

                    var propName = (string)kv.Key.Value;
                    if (!props.TryGetValue(propName, out var prop))
                    {
                        throw new MPConversionException(type, mpo,
                                                        message: $"can't resolve property from name [{propName}]");
                    }

                    var value = ctx.Decode(prop.PropertyType, kv.Value);
                    prop.SetValue(inst, value);
                }

                return(inst);
            }

            throw new MPConversionException(type, mpo,
                                            message: $"could not decode [{mpo.Type}] as object");
        }
Beispiel #14
0
        /// <summary>Creates a <see cref="ControlConverter"/> for a control.</summary>
        /// <param name="obj">The control to convert.</param>
        /// <param name="context">The context in which the conversion takes place.</param>
        /// <param name="writer">XML writer to receive the converted HTML.</param>
        /// <param name="args">Arguments for the conversion.</param>
        /// <returns></returns>
        public static IControlConverter Convert(object obj, IConverterContext context, XmlWriter writer, ConverterArguments args)
        {
            Type originaltype, type, convertertype = null;

            // ascend the derivation path until ...
            type = originaltype = obj.GetType();
            while (null != type)
            {
                // a previously used converter matches
                if (_typemap.TryGetValue(type, out convertertype))
                {
                    break;
                }

                // or a converter existings in the Factory namespace.
                if (null != (convertertype = LookupConverter(type)))
                {
                    break;
                }

                type = type.BaseType;
            }

            if (null == convertertype)
            {
                throw new Exception("unable to convert [" + obj.GetType().FullName + "].");
            }

            // using a baseclass converter?
            var baseclassconverter = type != originaltype;

            /*if(originaltype.GetCustomAttributes(false).OfType<GeneratorIgnoreAttribute>().Any())
            {
                baseclassconverter = false;
            }*/

            // TraceTarget.Trace("using [{0}] to convert [{1}] ...", convertertype.FullName, originaltype.FullName);

            // construct the converter object
            var constructor = convertertype.GetConstructor(new Type[0]);
            if (null == constructor)
            {
                throw new ConverterException(ErrorCode.InvalidConverterType, 
                    "type [" + convertertype.FullName + "] constructor unavailable.");
            }

            var converter = constructor.Invoke(new object[0]) as IControlConverter;
            if (null == converter)
            {
                throw new ConverterException(ErrorCode.InvalidConverterType, 
                    "type [" + convertertype.FullName + "] does not support converter interface.");
            }

            converter.Context = context;
            converter.IsSubClass = baseclassconverter;
            converter.SetControl(obj);
            converter.Convert(writer, args);

            if (converter.IsTypeRegistrable)
            {
                // add reference ...
                context.TriggerItemReference(originaltype.FullName);
            }

            return converter;
        }
Beispiel #15
0
        public MPObject Encode(IConverterContext ctx, Type type, object obj)
        {
            // Take care of Nullable<> values with null value now
            if (obj == null)
            {
                return(MPObject.Nil);
            }

            // Boolean
            if (type == typeof(bool))
            {
                return(((bool)obj) ? MPObject.True : MPObject.False);
            }
            if (type == typeof(bool?))
            {
                return((((bool?)obj).Value) ? MPObject.True : MPObject.False);
            }

            // Integer
            if (type == typeof(byte))
            {
                return(new MPObject(MPType.Integer, (byte)obj));
            }
            if (type == typeof(byte?))
            {
                return(new MPObject(MPType.Integer, ((byte?)obj).Value));
            }

            if (type == typeof(sbyte))
            {
                return(new MPObject(MPType.Integer, (sbyte)obj));
            }
            if (type == typeof(sbyte?))
            {
                return(new MPObject(MPType.Integer, ((sbyte?)obj).Value));
            }

            if (type == typeof(short))
            {
                return(new MPObject(MPType.Integer, (short)obj));
            }
            if (type == typeof(short?))
            {
                return(new MPObject(MPType.Integer, ((short?)obj).Value));
            }

            if (type == typeof(ushort))
            {
                return(new MPObject(MPType.Integer, (ushort)obj));
            }
            if (type == typeof(ushort?))
            {
                return(new MPObject(MPType.Integer, ((ushort?)obj).Value));
            }

            if (type == typeof(int))
            {
                return(new MPObject(MPType.Integer, (int)obj));
            }
            if (type == typeof(int?))
            {
                return(new MPObject(MPType.Integer, ((int?)obj).Value));
            }

            if (type == typeof(uint))
            {
                return(new MPObject(MPType.Integer, (uint)obj));
            }
            if (type == typeof(uint?))
            {
                return(new MPObject(MPType.Integer, ((uint?)obj).Value));
            }

            if (type == typeof(long))
            {
                return(new MPObject(MPType.Integer, (long)obj));
            }
            if (type == typeof(long?))
            {
                return(new MPObject(MPType.Integer, ((long?)obj).Value));
            }

            if (type == typeof(ulong))
            {
                return(new MPObject(MPType.Integer, (ulong)obj));
            }
            if (type == typeof(ulong?))
            {
                return(new MPObject(MPType.Integer, ((ulong?)obj).Value));
            }

            if (type == typeof(char))
            {
                return(new MPObject(MPType.Integer, (char)obj));
            }
            if (type == typeof(char?))
            {
                return(new MPObject(MPType.Integer, ((char?)obj).Value));
            }

            // Float
            if (type == typeof(float))
            {
                return(new MPObject(MPType.Float, (float)obj));
            }
            if (type == typeof(float?))
            {
                return(new MPObject(MPType.Float, ((float?)obj).Value));
            }

            if (type == typeof(double))
            {
                return(new MPObject(MPType.Float, (double)obj));
            }
            if (type == typeof(double?))
            {
                return(new MPObject(MPType.Float, ((double?)obj).Value));
            }

            if (type == typeof(decimal))
            {
                return(new MPObject(MPType.Float, (decimal)obj));
            }
            if (type == typeof(decimal?))
            {
                return(new MPObject(MPType.Float, ((decimal?)obj).Value));
            }

            // Binary
            if (type == typeof(byte[]))
            {
                return(new MPObject(MPType.Binary, (byte[])obj));
            }

            // String
            if (type == typeof(string))
            {
                return(new MPObject(MPType.String, (string)obj));
            }

            throw new MPConversionException(type,
                                            message: $"cannot encode from non-basic target type [{type.FullName}]");
        }
Beispiel #16
0
        public object Decode(IConverterContext ctx, Type type, MPObject mpo)
        {
            // Boolean
            if (type == typeof(bool))
            {
                return(Decode <bool>(ctx, mpo, MPType.Boolean));
            }
            if (type == typeof(bool?))
            {
                return(Decode <bool?>(ctx, mpo, MPType.Boolean));
            }

            // Integer
            if (type == typeof(byte))
            {
                return(Decode <byte>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(byte?))
            {
                return(Decode <byte?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(sbyte))
            {
                return(Decode <sbyte>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(sbyte?))
            {
                return(Decode <sbyte?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(short))
            {
                return(Decode <short>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(short?))
            {
                return(Decode <short?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(ushort))
            {
                return(Decode <ushort>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(ushort?))
            {
                return(Decode <ushort?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(int))
            {
                return(Decode <int>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(int?))
            {
                return(Decode <int?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(uint))
            {
                return(Decode <uint>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(uint?))
            {
                return(Decode <uint?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(long))
            {
                return(Decode <long>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(long?))
            {
                return(Decode <long?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(ulong))
            {
                return(Decode <ulong>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(ulong?))
            {
                return(Decode <ulong?>(ctx, mpo, MPType.Integer));
            }

            if (type == typeof(char))
            {
                return(Decode <char>(ctx, mpo, MPType.Integer));
            }
            if (type == typeof(char?))
            {
                return(Decode <char?>(ctx, mpo, MPType.Integer));
            }

            // Float
            if (type == typeof(float))
            {
                return(Decode <float>(ctx, mpo, MPType.Float));
            }
            if (type == typeof(float?))
            {
                return(Decode <float?>(ctx, mpo, MPType.Float));
            }

            if (type == typeof(double))
            {
                return(Decode <double>(ctx, mpo, MPType.Float));
            }
            if (type == typeof(double?))
            {
                return(Decode <double?>(ctx, mpo, MPType.Float));
            }

            if (type == typeof(decimal))
            {
                return(Decode <decimal>(ctx, mpo, MPType.Float));
            }
            if (type == typeof(decimal?))
            {
                return(Decode <decimal?>(ctx, mpo, MPType.Float));
            }

            // Binary
            if (type == typeof(byte[]))
            {
                return(Decode <byte[]>(ctx, mpo, MPType.Binary));
            }

            // String
            if (type == typeof(string))
            {
                return(Decode <string>(ctx, mpo, MPType.String));
            }

            throw new MPConversionException(type, mpo,
                                            message: $"cannot decode into non-basic target type [{type.FullName}]");
        }
 private static bool TryParseWithContext(IConverterContext <string> context, out DateTime dateTime)
 {
     return(DateTime.TryParse(context.SourceValue, out dateTime));
 }
Beispiel #18
0
        public object Decode(IConverterContext ctx, Type type, MPObject mpo)
        {
            if (mpo.Type == MPType.Nil)
            {
                if (!type.IsValueType)
                {
                    return(null);
                }
                else
                {
                    throw new MPConversionException(type, mpo,
                                                    message: $"cannot return null value for target type [{type.FullName}]");
                }
            }

            if (mpo.Type == MPType.Array)
            {
                var mpoArray = (IList <MPObject>)mpo.Value;

                if (type.IsArray)
                {
                    var itemType = type.GetElementType();
                    var arr      = Array.CreateInstance(itemType, mpoArray.Count);
                    var ndx      = 0;
                    foreach (var mpoItem in mpoArray)
                    {
                        var item = ctx.Decode(itemType, mpoItem);
                        arr.SetValue(item, ndx++);
                    }
                    return(arr);
                }

                var gt = Util.GetSubclassOfGenericTypeDefinition(typeof(IList <>), type);
                if (gt != null)
                {
                    var instType = type;
                    var itemType = gt.GenericTypeArguments[0];
                    // If the target type is interface of IList<>, then
                    // we construct a concrete instance type of List<>
                    if (instType.GetGenericTypeDefinition() == typeof(IList <>))
                    {
                        instType = typeof(List <>).MakeGenericType(itemType);
                    }
                    var inst = Activator.CreateInstance(instType);
                    var meth = instType.GetMethod(nameof(IList <object> .Add), new[] { itemType });
                    foreach (var mpoItem in mpoArray)
                    {
                        var item = ctx.Decode(itemType, mpoItem);
                        meth.Invoke(inst, new[] { item });
                    }
                    return(inst);
                }

                if (typeof(IList).IsAssignableFrom(type))
                {
                    var arr = type == typeof(IList)
                        ? new ArrayList(mpoArray.Count)
                        : (IList)Activator.CreateInstance(type);
                    foreach (var mpoItem in mpoArray)
                    {
                        var item = ctx.Decode(typeof(object), mpoItem);
                        arr.Add(item);
                    }
                    return(arr);
                }
            }

            throw new MPConversionException(type, mpo,
                                            message: $"could not decode [{mpo.Type}] as array object");
        }
 IControlConverter IConverterContext.Convert(object obj, XmlWriter writer, IConverterContext context, ConverterArguments args)
 {
     return HtmlFactory.Convert(obj, context ?? (this as IConverterContext), writer, args);
 }
        public void GenerateDataTemplate(DataTemplate template, XmlWriter writer, IConverterContext context)
        {
            if (null == context)
            {
                context = this as IConverterContext;
            }

            // purportedly the only place where data templates get started ...
            context.Convert(template, writer);
        }