Frage

Ich möchte die Eigenschaften eines Objekts füllen, ohne Reflexion in ähnlicher Weise wie bei der DynamicBuilder auf Codeproject . Das Codeproject Beispiel ist zugeschnitten Entitäten zum Bestücken eines Datareader oder Datarecord verwenden. Ich benutze dies in mehreren DALs um eine gute Wirkung. Jetzt möchte ich ändern es ein Wörterbuch oder andere Daten Agnostiker Objekt zu verwenden, so dass ich es in nicht DAL Code --places verwenden kann ich zur Zeit Reflexion verwenden. Ich weiß fast nichts über OpCodes und IL. Ich weiß nur, dass es funktioniert gut und ist schneller als Reflexion.

Ich habe versucht, die Codeproject Beispiel und wegen meiner Unwissenheit mit IL zu ändern, ich habe auf zwei Zeilen stecken geblieben.

  • Einer von ihnen beschäftigt sich mit dbnulls und ich bin mir ziemlich sicher, dass ich es nur verlieren kann, aber ich weiß nicht, ob die Zeilen davor und danach beziehen und die von ihnen werden auch gehen müssen.
  • Die andere, glaube ich, ist derjenige, der den Wert aus dem Datarecord zog vor und muss nun aus dem Wörterbuch ziehen. Ich glaube, ich kann die „getValueMethod“ mit meinem „property.Value“ ersetzen, aber ich bin mir nicht sicher.

Ich bin offen für alternative / bessere Wege zu dieser Katze häuten.

Hier ist der Code so weit (die auf Kommentar Linien sind die, die ich auf bin stecken):

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

EDIT:

Marc GRA der PropertyDescriptor Implementierung Verwendung (mit HyperDescriptor) den Code hundertfach vereinfacht. Ich habe jetzt den folgenden 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]);
        }
    }
}

Jede Kommentare zu Leistungsinformationen für beide TypeDescriptor.GetProperties () & PropertyDescriptor.SetValue () sind willkommen ...

War es hilfreich?

Lösung

Edit: all dies ist im Grunde, was adrett tut - aber adrett ist wesentlich optimiert. Wenn ich diese Antwort heute schreibe, wäre es einfach zu lesen: „verwenden. Adrett“


Wenn Sie nicht sehr groß „up“ auf IL sind, gibt es Alternativen, die die Geschwindigkeit von IL und die Bequemlichkeit der Reflexion erhalten.

Erstes Beispiel:

HyperDescriptor - verwendet ein benutzerdefiniertes PropertyDescriptor Modell, das mit dem IL Angebote für Sie, so alles, was Sie haben, ist Code wie (plus die Einzeiler HyperDescriptor zu ermöglichen):

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

Zweites Beispiel:

LINQ Ausdrücke - recht lang, aber ich habe diese diskutiert (und die oben, es stellt sich heraus) zum direkten Download - siehe dieses Archiv .

Andere Tipps

Ja, können Sie folgenden Code verwenden:

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

.... ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top