Ich möchte die Eigenschaften eines Objekts ohne Verwendung von Reflektion auf ähnliche Weise wie DynamicBuilder on CodeProject auffüllen. Das CodeProject-Beispiel ist auf das Füllen von Entitäten mit einem DataReader oder DataRecord zugeschnitten. Ich benutze dies in mehreren DALs mit gutem Erfolg. Jetzt möchte ich es ändern, um ein Wörterbuch oder ein anderes datenunabhängiges Objekt zu verwenden, so dass ich es in Nicht-DAL-Code verwenden kann - Orte, an denen ich derzeit Reflektion verwende. Ich weiß fast nichts über OpCodes und IL. Ich weiß einfach, dass es gut funktioniert und schneller ist als Nachdenken.Dynamischer Objekteigenschaften-Populator (ohne Reflektion)
Ich habe versucht, das 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 verbunden sind und welche von ihnen werden auch gehen müssen.
- Die andere, glaube ich, ist derjenige, der den Wert aus dem Datarecord vor und jetzt ist es aus dem Wörterbuch zu ziehen braucht gezogen. Ich denke, ich kann die "getValueMethod" mit meinem "property.Value" ersetzen, aber ich bin mir nicht sicher.
Ich bin offen für alternative/bessere Möglichkeiten, diese Katze auch zu enthä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:
Mit Marc GRA der PropertyDescriptor Implementierung (mit HyperDescriptor) den Code vereinfacht ein Hundertfaches. 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]);
}
}
}
Alle Kommentare zu Leistungsinformationen für beide TypeDescriptor.GetProperties() & PropertyDescriptor.SetValue() sind willkommen ...
(antwortete Kommentar) –