动态对象属性填充器(无反射) [英] Dynamic object property populator (without reflection)

查看:279
本文介绍了动态对象属性填充器(无反射)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想没有在类似的方式使用反射来填充一个对象的属性DynamicBuilder在CodeProject 。 CodeProject上的例子是用于填充使用DataReader或DataRecord实体量身定做。我在几个DALS效果良好使用。现在我想修改它使用字典或者其他数据无关的对象,这样我可以在我目前使用反射非DAL代码--places使用它。我几乎一无所知操作码和IL。我只知道,它运作良好,比反射快。

I want to populate an object's properties without using reflection in a manner similar to the DynamicBuilder on CodeProject. The CodeProject example is tailored for populating entities using a DataReader or DataRecord. I use this in several DALs to good effect. Now I want to modify it to use a dictionary or other data agnostic object so that I can use it in non DAL code --places I currently use reflection. I know almost nothing about OpCodes and IL. I just know that it works well and is faster than reflection.

我试图修改CodeProject上的例子,因为我的无知与IL,我已经得到了卡上的两个行。

I have tried to modify the CodeProject example and because of my ignorance with IL, I have gotten stuck on two lines.


  • 其中一人与dbnulls交易和我敢肯定,我可以失去它,但我不知道是否前面和后面它是相关的,这其中也需要走线。

  • 另外,我认为,是拉值之前的datarecord的一个,现在需要拉出来的字典。我想我可以用我的property.Value取代getValueMethod,但我不知道。

我开。太剥皮这种猫的替代/更好的办法

I'm open to alternative/better ways of skinning this cat too.

下面是到目前为止的代码(注释掉线是那些我卡上):

Here's the code so far (the commented out lines are the ones I'm stuck on):

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

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>();
        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;
    }
}



编辑:

使用马克·Gravell的实施的PropertyDescriptor(与HyperDescriptor)代码被简化百倍。我现在有以下测试:

Using Marc Gravell's PropertyDescriptor implementation (with HyperDescriptor) the code is simplified a hundred-fold. I now have the following test:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Hyper.ComponentModel;

namespace Test
{
    class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    class Program
    {
        static void Main()
        {
            HyperTypeDescriptionProvider.Add(typeof(Person));
            var properties = new Dictionary<string, object> { { "Id", 10 }, { "Name", "Fred Flintstone" } };
            Person person = new Person();
            DynamicUpdate(person, properties);
            Console.WriteLine("Id: {0}; Name: {1}", person.Id, person.Name);
            Console.ReadKey();
        }

        public static void DynamicUpdate<T>(T entity, Dictionary<string, object> properties)
        {
            foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(typeof(T)))
                if (properties.ContainsKey(propertyDescriptor.Name))
                    propertyDescriptor.SetValue(entity, properties[propertyDescriptor.Name]);
        }
    }
}

有关性能方面的考虑任何评论既TypeDescriptor.GetProperties()及PropertyDescriptor.SetValue(),欢迎...

Any comments on performance considerations for both TypeDescriptor.GetProperties() & PropertyDescriptor.SetValue() are welcome...

推荐答案

编辑:这一切基本上是短小精悍的那样 - 但短小精悍得多更加优化。如果我今天在写这个答案,它只会显示为:用短小精悍

all of this is basically what dapper does - but dapper is much more optimized. If I was writing this answer today, it would read simply: "use dapper".

如果你不是非常向上的IL,有让你IL的速度和反射的方便的替代品

If you aren't hugely "up" on IL, there are alternatives that get you the speed of IL and the convenience of reflection.

第一个例子:

HyperDescriptor - 使用自定义的的PropertyDescriptor 模式与IL为你的交易,所以你必须像码(加单行,使 HyperDescriptor ):

HyperDescriptor - uses a custom PropertyDescriptor model that deals with the IL for you, so all you have is code like (plus the one-liner to enable HyperDescriptor):

public static IEnumerable<T> Read<T>(IDataReader reader) where T : class, new() 
{
    PropertyDescriptorCollection props =
        TypeDescriptor.GetProperties(typeof(T));

    PropertyDescriptor[] propArray = new PropertyDescriptor[reader.FieldCount];
    for (int i = 0; i < propArray.Length; i++)
    {
        propArray[i] = props[reader.GetName(i)];
    }
    while(reader.Read()) {
        T item = new T();
        for (int i = 0; i < propArray.Length; i++)
        {
            object value = reader.IsDBNull(i) ? null : reader[i];
            propArray[i].SetValue(item, value);
        }
        yield return item;
    }
}



第二个例子:

Second example:

LINQ表达式 - 相当长,但我已经讨论过这个(及以上,原来)Usenet上 - 看到的此存档

LINQ expressions - quite lengthy, but I've discussed this (and the above, it turns out) on usenet - see this archive.

这篇关于动态对象属性填充器(无反射)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆