views:

46

answers:

1

Hey

We are about to do some reflector in my company.

I need a FactoryClass that can convert an IDictionary to a obj, by doing a match on properties and dict keys.

I found:

http://stackoverflow.com/questions/1273589/dynamic-object-property-populator-without-reflection

This code can do what I want, and I want to use this code, because it is done by using the basic of dotNET without using others extensions.

public class Populator<T>
{
    private delegate T Load(Dictionary<string, object> properties);
    private Load _handler;
    private Populator() { }
    public T Build(Dictionary<string, object> properties)
    {
        return _handler(properties);
    }
public static Populator<T> CreateBuilder(Dictionary<string, object> properties)
{
    //private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new [] { typeof(int) });
    //private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new [] { typeof(int) });
    Populator<T> dynamicBuilder = new Populator<T>();
    ...

When I tested this code, I got an error.

public ICollection<object> GetKeys(IDictionary<object, object> products)
    {
        IDictionary<object, object> product = (IDictionary<object, object>)products.ElementAt(0).Value;

        Dictionary<string, object> p = new Dictionary<string, object>();
        foreach (KeyValuePair<object, object> item in product)
        {
            p.Add(item.Key.ToString(), item.Value);
        }

        Populator<ProductTest> builder = Populator<ProductTest>.CreateBuilder(p);
        ProductTest obj = builder.Build(p); // error here


        return null;
    }

I got and error here

    public class Populator<T>
{
    private delegate T Load(Dictionary<string, object> properties);
    private Load _handler;
    private Populator() { }
    public T Build(Dictionary<string, object> properties)
    {
        return _handler(properties); // Error: JIT Compiler encountered an internal limitation.
    }

Wy question is then why, and how to solve it ? There is nothing in extra in the stacktrace.

// dennis

A: 

Here is the class with some test code, and the mapper with the error. You only need to init the klasse.

// http://stackoverflow.com/questions/1273589/dynamic-object-property-populator-without-reflection

namespace Test

{

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Reflection;
using System.Reflection.Emit;


public class ProductTest
{

    public string ProductGuid { get; set; }
    public string ProductName { get; set; }

}

/// <summary>
/// Summary description for ProductMapper
/// </summary>
public class ProductMapper
{
    public ProductMapper()
    {
        DoTheMagic();
    }
    public ICollection<object> DoTheMagic()
    {
        Dictionary<string, object> product = new Dictionary<string, object>();


        product["ProductGuid"] = "Product Id";
        product["ProductName"] = "Product Name";


        Populator<ProductTest> builder = Populator<ProductTest>.CreateBuilder(product);
        ProductTest obj = builder.Build(product);


        return null;
    }
}




public class Populator<T>
{
    private delegate T Load(Dictionary<string, object> properties);
    private Load _handler;
    private Populator() { }
    public T Build(Dictionary<string, object> properties)
    {
        T obj = default(T);
        try
        {
            obj = _handler(properties); // JIT Compiler encountered an internal limitation.
        }
        catch (Exception ex)
        {
            string s = ex.Message;
        }

        return obj;
    }
    public static Populator<T> CreateBuilder(Dictionary<string, object> properties)
    {
        //private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new [] { typeof(int) });
        //private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new [] { typeof(int) });
        Populator<T> dynamicBuilder = new Populator<T>();
        DynamicMethod method = new DynamicMethod("Create", typeof(T), new[] { typeof(Dictionary<string, object>) }, typeof(T), true);
        ILGenerator generator = method.GetILGenerator();

        LocalBuilder result = generator.DeclareLocal(typeof(T));
        generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
        generator.Emit(OpCodes.Stloc, result);

        int i = 0;
        foreach (var property in properties)
        {
            PropertyInfo propertyInfo = typeof(T).GetProperty(property.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy | BindingFlags.Default);
            Label endIfLabel = generator.DefineLabel();

            if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
            {
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldc_I4, i);
                //generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                generator.Emit(OpCodes.Brtrue, endIfLabel);

                generator.Emit(OpCodes.Ldloc, result);
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldc_I4, i);
                //generator.Emit(OpCodes.Callvirt, getValueMethod);

                generator.Emit(OpCodes.Unbox_Any, property.Value.GetType());
                generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                generator.MarkLabel(endIfLabel);
            }
            i++;
        }

        generator.Emit(OpCodes.Ldloc, result);
        generator.Emit(OpCodes.Ret);

        dynamicBuilder._handler = (Load)method.CreateDelegate(typeof(Load));
        return dynamicBuilder;
    }
}

}

Hope this helps.

Dennis Larsen
Hi, and welcome to Stack Overflow, but please edit this into your question and delete it. SO is not really a discussion board, so this answer will quickly fall down below/between other answers. Now it looks like you answered your question, instead of providing more information for your question. Just a heads up :)
Lasse V. Karlsen
How can I add the content.
Dennis Larsen
I cant do it in the comment field, it is to small :S
Dennis Larsen