2013-07-29 2 views
1

는이 코드를 가지고 :NewExpression에 대한 참조를 어떻게 보관합니까?

긴 이야기의 짧은 <T>에 데이터베이스 행의 속성을 결합
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; 
} 

. 문제는 내가 사용하고자 할 때/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하지만 블록 식 내부에 return식이 필요하지 않습니까? 그렇지 않으면 람다 식은 반환 값을 가지지 않을 것입니다, 그렇습니까? –

+1

@ p.sw.gr, IIRC 블록의 마지막 표현식이 반환 값으로 사용됩니다. 그것이 그의 코드에서 OP가 이미하고있는 것입니다. –

+0

알겠습니다. 고마워요. 나는 정말로 확실하지 않았다. 나는 알고있다'Func f = x => {5; }'C#에서는'return 5; '가 필요하기 때문에 컴파일되지 않습니다. 수동으로 표현식을 만들 때도 같을 것이라고 생각했습니다. –

3

나는 멤버하는 초기화/바인딩 표현보다는 세터의 시리즈를 사용하는 것이 좋습니다 것입니다 : 당신은 같은 재사용 할 의미

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 도움이 된 것을 기쁘게 생각합니다. 해피 코딩 :) –