문제

나는 CodeProject의 DynamicBuilder. CodeProject 예제는 DataReader 또는 DataRecord를 사용하여 채워진 엔티티에 맞게 조정됩니다. 나는 이것을 여러 dals에서 좋은 효과로 사용합니다. 이제 사전 또는 기타 데이터가 불가지론 객체를 사용하여 비 DAL 코드로 사용할 수 있도록 수정하고 싶습니다. 현재 반사를 사용하고 있습니다. 나는 Opcodes와 Il에 대해 거의 아무것도 모른다. 나는 그것이 잘 작동하고 반사보다 빠르다는 것을 알고 있습니다.

나는 CodeProject 예제를 수정하려고 노력했으며 IL에 대한 무지 때문에 두 줄에 붙어 있습니다.

  • 그들 중 하나는 dbnulls를 다루고 있으며 나는 그것을 잃을 수 있다고 확신하지만, 앞서 나 따르는 줄이 관련되어 있는지, 그리고 그 중 어느 쪽도 갈 필요가 있는지 모르겠습니다.
  • 다른 하나는 이전에 Datarecord에서 값을 꺼내고 이제 사전에서 꺼내야한다고 생각합니다. 나는 "getValuemethod"를 내 "property.value"로 바꿀 수 있다고 생각하지만 확실하지 않습니다.

나는이 고양이들도 대안/더 나은 방법에 열려 있습니다.

지금까지 코드는 다음과 같습니다 (댓글이 붙은 줄은 내가 붙어있는 줄입니다).

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

편집하다:

Marc Gravell의 PropertyDescriptor 구현 (HyperDescriptor 포함)을 사용하여 코드는 백포도로 단순화됩니다. 이제 다음과 같은 테스트를 받았습니다.

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 ()에 대한 성능 고려 사항에 대한 의견은 환영합니다 ...

도움이 되었습니까?

해결책

편집 :이 모든 것은 기본적으로 Dapper가하는 일이지만 Dapper는 훨씬 더 최적화됩니다. 오늘이 답변을 쓰고 있다면 간단하게 "Dapper 사용"을 읽을 것입니다.


IL에서 "Up"이 크지 않으면 IL의 속도와 반사의 편의성을 얻는 대안이 있습니다.

First example:

hyperdescriptor - 사용자 정의를 사용합니다 PropertyDescriptor 당신을 위해 IL을 다루는 모델이므로, 당신이 가진 모든 것은 코드와 같은 것입니다 (하나의 라이너를 활성화 할 수 있습니다. 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에서 이것 (위의 내용)에 대해 논의했습니다. 이 아카이브.

다른 팁

예, 다음과 같은 코드를 사용할 수 있습니다.

 for (int i = 0; i < dataRecord.FieldCount; i++)
                {

                    PropertyInfo propertyInfo = t.GetProperty(dataRecord.GetName(i));
                    LocalBuilder il_P = generator.DeclareLocal(typeof(PropertyInfo));

                    Label endIfLabel = generator.DefineLabel();

.... ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top