2011-07-01 36 views
3

我有一個程序集和一些類。我想要做的就是創建一個類的實例,並且在一般的方式填充它的屬性,是這樣的:Reflection.Emit和Instantiation

public T FillObject(IDictionary<string,object> values) 
{ 
    /// CREATE INSTANCE 
    /// FILL THE PROPERTIES WITH THE VALUES 
} 

反思是最好的方式,但它的速度太慢,而不是我聽說的反思.Emit速度更快,那麼是否有辦法實例化類並使用Reflection.Emit填充其屬性?

在此先感謝您的幫助。

回答

6

在這種情況下,我建議HyperDescriptor;它是好像的反映,但用IL代拋出中間表現;那麼,您只需使用常規元件型號代碼:

object obj = Activator.CreateInstance(typeof(T)); 
var props = TypeDescriptor.GetProperties(typeof(T)); 
foreach(var pair in data) 
{ 
    props[pair.Key].SetValue(obj, pair.Value); 
} 

編輯;對於有點2012的更新,FastMember涉及較少的抽象:

var accessor = TypeAccessor.Create(typeof(T)); 
foreach(var pair in data) 
{ 
    accessor[obj, pair.Key] = pair.Value; 
} 

除了是更直接,FastMember將與正常dynamic類型的工作,太 - 不只是反射。

+0

我以前沒見過。井井有條。 –

+0

謝謝Marc,最好的解決方案。 – Argons

2

Dapper.NET這樣做。這是一個Micro-ORM,可以提供強大的計算能力。整個ORM只是一個C#文件。

http://code.google.com/p/dapper-dot-net/source/browse/Dapper/SqlMapper.cs

創建動態方法相關的代碼是這樣的:

var method = new DynamicMethod(commandType.Name + "_BindByName", null, new Type[] { typeof(IDbCommand), typeof(bool) }); 
var il = method.GetILGenerator(); 
il.Emit(OpCodes.Ldarg_0); 
il.Emit(OpCodes.Castclass, commandType); 
il.Emit(OpCodes.Ldarg_1); 
il.EmitCall(OpCodes.Callvirt, setter, null); 
il.Emit(OpCodes.Ret); 
action = (Action<IDbCommand, bool>)method.CreateDelegate(typeof(Action<IDbCommand, bool>)); 

還要注意的是IKVM.NET項目提供自己的實現的IKVM.Reflection.Emit了一些改進。如果你從頭開始,可以把它看作是另一種選擇。

+0

請注意,我們的優勢在於數據網格趨向的故事具有相同的列 - 不一定與字典地圖一致;類似的東西可以工作,但它會更復雜,因爲它需要開啓按鍵。 –

+0

@Marc Gravell,確實如此,但是如果要創建一個'T'的實例,那麼這可能是一個很好的假設,即字典鍵將是相同的。除此之外,映射鍵不是問題的一部分。 :-)最後,Dapper.NET真的很棒,所以任何炒作的機會都不錯。我希望更多的框架將使用Reflection.Emit而不是普通的Reflection。 –

+0

有中間選擇,雖然(短小精悍真的是非常專業的,我不知道我會用它作爲比較這裏...) –

3

如果您使用的是.Net 4,則可以使用新的Expression類型(已添加以支持dynamic),以創建表達式來分配屬性,將其編譯爲委託,並重復調用該表達式。性能應該與使用Reflection.Emit相媲美。

class ObjectFiller<T> 
{ 
    private static Func<IDictionary<string, object>, T> FillerDelegate; 

    private static void Init() 
    { 
     var obj = Expression.Parameter(typeof(T), "obj"); 
     var valuesDictionary = Expression.Parameter(typeof(IDictionary<string, object>), "values"); 

     var create = Expression.Assign(
      obj, Expression.Call(typeof(Activator), "CreateInstance", new[] { typeof(T) })); 

     var properties = typeof(T).GetProperties(); 

     var setters = Expression.Block(properties.Select(p => CreateSetter(p, obj, valuesDictionary))); 

     var methodBody = Expression.Block(typeof(T), new[] { obj }, create, setters, obj); 

     var fillerExpression = Expression.Lambda<Func<IDictionary<string, object>, T>>(methodBody, valuesDictionary); 

     FillerDelegate = fillerExpression.Compile(); 
    } 

    static Expression CreateSetter(PropertyInfo property, Expression obj, Expression valuesDictionary) 
    { 
     var indexer = Expression.MakeIndex(
      valuesDictionary, 
      typeof(IDictionary<string, object>).GetProperty("Item", new[] { typeof(string) }), 
      new[] { Expression.Constant(property.Name) }); 

     var setter = Expression.Assign(
      Expression.Property(obj, property), 
      Expression.Convert(indexer, property.PropertyType)); 

     var valuesContainsProperty = Expression.Call(
      valuesDictionary, "ContainsKey", null, Expression.Constant(property.Name)); 

     var condition = Expression.IfThen(valuesContainsProperty, setter); 

     return condition; 
    } 

    public T FillObject(IDictionary<string, object> values) 
    { 
     if (FillerDelegate == null) 
      Init(); 
     return FillerDelegate(values); 
    } 
} 

你可以做的.Net 3非常相似的東西太多,使用Expression版本對象初始化的。

0

這是一篇關於如何從數據庫IDatarecord進行映射的示例文章。 它很容易這個適應大多數情況下

動態......但快速:三隻猴子,狼和DynamicMethod的和的ILGenerator類 http://www.codeproject.com/KB/database/DynamicMethod_ILGenerator.aspx

+0

這個鏈接已經死了,你有什麼機會找到替代品? –

+0

http://www.codeproject.com/Articles/19513/Dynamic-But-Fast-The-Tale-of-Three-Monkeys-A-Wolf – rqmedes