2013-07-29 108 views
1

我有這樣的代碼:你如何持有對NewExpression的引用?

public static Func<IDataReader, T> CreateBinder<T>() { 

    NewExpression dataTransferObject = Expression.New(typeof(T).GetConstructor(Type.EmptyTypes)); 
    ParameterExpression dataReader = Expression.Parameter(typeof(IDataReader), "reader"); 

    IEnumerable<Expression> columnAssignments = typeof(T).GetProperties().Select(property => { 
     MethodCallExpression columnData = Expression.Call(dataReader, dataReaderIndexer, new[] { Expression.Constant(property.Name) }); 
     MethodCallExpression setter = Expression.Call(dataTransferObject, property.SetMethod, new[] { Expression.Convert(columnData, property.PropertyType) }); 

     return setter; 
    }); 

    columnAssignments = columnAssignments.Concat(new Expression[] { dataTransferObject }); 
    BlockExpression assignmentBlock = Expression.Block(columnAssignments); 

    Func<IDataReader, T> binder = Expression.Lambda<Func<IDataReader, T>>(assignmentBlock, new[] { dataReader }).Compile(); 

    return binder; 
} 

這長話短說結合對數據庫行的屬性<T>。問題是,當我想使用/返回dataTransferObject時,它每次都實例化一個新副本。我如何獲得參考,而不重新創建對象?

+0

你的意思是要重複使用相同的任何給定類型'T'的'binder'? –

+0

由於'dataTransferObject'是一個'NewExpression',每次使用它時,它都會創建一個新的實例,而不是重複使用同一個實例。就像我在調用setter方法時,它正在執行'new T()。Property''而不是重用先前實例化的對象。 – sircodesalot

回答

3

您只需將NewExpression分配給一個變量,然後使用該變量而不是NewExpression

var dataTransferObject = Expression.Variable(typeof(T), "dto"); 
var assignment = Expression.Assign(
        dataTransferObject, 
        Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))); 

(添加這些表達式給BlockExpression

+0

+1,但是你不需要在塊表達式中使用返回表達式嗎?否則,lambda表達式不會有返回值,對吧? –

+1

@ p.s.w.g,IIRC塊中的最後一個表達式用作返回值;這就是OP已經在他的代碼中做的事情。 –

+0

好的,謝謝。我真的不確定。我知道'Func f = x => {5; }'不會在C#中編譯,因爲你需要'return 5;'。我覺得手動構建表達式的時候是一樣的。 –

3

我建議你使用成員intialization /綁定表達式,而不是一系列setter方法:

public static Func<IDataReader, T> CreateBinder<T>() 
{ 
    NewExpression dataTransferObject = Expression.New(typeof(T).GetConstructor(Type.EmptyTypes)); 
    ParameterExpression dataReader = Expression.Parameter(typeof(IDataReader), "reader"); 

    IEnumerable<MemberBinding > bindings = typeof(T).GetProperties().Select(property => { 
     MethodCallExpression columnData = Expression.Call(dataReader, dataReaderIndexer, new[] { Expression.Constant(property.Name) }); 
     MemberBinding binding = Expression.Binding(property, Expression.Convert(columnData, property.PropertyType)); 

     return binding; 
    }); 

    Expression init = Expression.MemberInit(dataTransferObject, bindings); 

    Func<IDataReader, T> binder = Expression.Lambda<Func<IDataReader, T>>(init, new[] { dataReader }).Compile(); 

    return binder; 
} 
+0

我同意,它更清潔。我很專注於解決OP所說的問題,我甚至沒有想到這個...... –

+0

是的,不回答最初的問題,但像一個魅力。我一定會用這個。 (儘管得到答案也很酷,呵呵) – sircodesalot

+0

@sircodesalot很高興幫助。快樂編碼:) –

相關問題