을 통해 DataTable을에 객체의 속성을 쓰기 나는이 간단한 모델의 목록이 있습니다 var list = new List<Test>() { /* some items here */ };
로식 트리
// model:
public class Test {
public int ID { get; set; }
public string Name { get; set; }
}
합니다. 그리고 나는이 조각하여 list
에서 DataTable
를 생성하고 있습니다 :
var dataTable = new DataTable();
dataTable.Columns.Add("ID", typeof(int));
dataTable.Columns.Add("Name", typeof(string));
foreach (var item in list) {
var dr = dataTable.NewRow();
dr["ID"] = item.ID;
dr["Name"] = item.Name;
dataTable.Rows.Add(dr);
}
이 지금은 실행시 위의 미리보기를 할 수있는 몇 가지 표현 트리를 생성하기 위해 노력하고있어 (일반적인 방법).
An exception of type 'System.InvalidOperationException' occurred in System.Core.dll but was not handled in user code
Additional information: variable 'item' of type 'TestEntity' referenced from scope '', but it is not defined
당신이 어떤 생각을 가지고 있습니까 : 나는이 오류가 (단지 return
전에, 블록의 끝에서) .Compile()
메서드를 호출 할 때,
private static Action<DataTable, IEnumerable<T>> GetAction() {
if (_filler != null)
return;
var type = typeof(T);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var tableParam = Expression.Parameter(typeof(DataTable), "targetTable");
var rowsParam = Expression.Parameter(typeof(IEnumerable<T>), "rows");
var loopVariable = Expression.Parameter(typeof(T), "item");
var columnsVariable = Expression.Parameter(typeof(DataColumnCollection), "columns");
var columnsAssign = Expression.Assign(columnsVariable,
Expression.Property(tableParam, typeof(DataTable).GetProperty("Columns")));
var headerExpressions = new List<Expression>();
var bodyExpressions = new List<Expression>();
var newRowParam = Expression.Parameter(typeof(DataRow), "currentRow");
var newRowAssign = Expression.Assign(newRowParam, Expression.Call(tableParam, typeof(DataTable).GetMethod("NewRow")));
foreach (var prop in props) {
var getMethod = prop.GetGetMethod(false);
if (getMethod == null)
continue;
var attr = prop.GetCustomAttribute<UdtColumnAttribute>();
var name = attr == null ? prop.Name : attr.ColumnName;
var headerNameParam = Expression.Parameter(typeof(string), "columnName");
var headerNameAssign = Expression.Assign(headerNameParam, Expression.Constant(name, typeof(string)));
var headerTypeParam = Expression.Parameter(typeof(Type), "columnType");
var headerTypeAssign = Expression.Assign(headerTypeParam, Expression.Constant(prop.PropertyType, typeof(Type)));
var columnsAddMethod = Expression.Call(columnsVariable,
typeof(DataColumnCollection).GetMethod("Add", new[] { typeof(string), typeof(Type) }),
headerNameParam, headerTypeParam);
headerExpressions.AddRange(new Expression[] {
headerNameParam,
headerNameAssign,
headerTypeParam,
headerTypeAssign,
columnsAddMethod,
});
var indexerProp = typeof(DataRow).GetProperty("Item", new[] { typeof(string) });
var indexerParam = Expression.Property(newRowParam, indexerProp, Expression.Constant(name, typeof(string)));
var propertyReaderMethod = Expression.Call(loopVariable, getMethod);
var assign = Expression.Assign(indexerParam, Expression.TypeAs(propertyReaderMethod, typeof(object)));
bodyExpressions.AddRange(new Expression[] { indexerParam, propertyReaderMethod, assign });
}
var finalExpressions = new List<Expression>() {
tableParam,
rowsParam,
loopVariable,
columnsVariable,
columnsAssign,
newRowParam,
newRowAssign,
};
finalExpressions.AddRange(headerExpressions);
var loop = ExpressionHelper.ForEach(rowsParam, loopVariable, Expression.Block(bodyExpressions));
finalExpressions.Add(loop);
var compilable = Expression.Block(finalExpressions);
var code = compilable.ToString();
Trace.WriteLine(code);
var compiled = Expression.Lambda<Action<DataTable, IEnumerable<T>>>(compilable, tableParam, rowsParam).Compile();
return compiled;
}
을하지만, 그러나, 내 시도는 여기에 날 잡았어 내가 여기서 뭘 놓쳤는가? 미리 감사드립니다. 건배.
UPDATE : 여기 는 루프 생성기입니다 :
public static class ExpressionHelper {
public static Expression ForEach(Expression collection, ParameterExpression loopVar, Expression loopContent) {
var elementType = loopVar.Type;
var enumerableType = typeof(IEnumerable<>).MakeGenericType(elementType);
var enumeratorType = typeof(IEnumerator<>).MakeGenericType(elementType);
var enumeratorVar = Expression.Variable(enumeratorType, "enumerator");
var getEnumeratorCall = Expression.Call(collection, enumerableType.GetMethod("GetEnumerator"));
var enumeratorAssign = Expression.Assign(enumeratorVar, getEnumeratorCall);
// The MoveNext method's actually on IEnumerator, not IEnumerator<T>
var moveNextCall = Expression.Call(enumeratorVar, typeof(IEnumerator).GetMethod("MoveNext"));
var breakLabel = Expression.Label("LoopBreak");
var loop = Expression.Block(new[] { enumeratorVar },
enumeratorAssign,
Expression.Loop(
Expression.IfThenElse(
Expression.Equal(moveNextCall, Expression.Constant(true)),
Expression.Block(new[] { loopVar },
Expression.Assign(loopVar, Expression.Property(enumeratorVar, "Current")),
loopContent
),
Expression.Break(breakLabel)
),
breakLabel)
);
return loop;
}
}
'loopVariable'은 매개 변수로 정의되어 있지만 람다에게 제공하지 마십시오. 그것에 대해'Expression.Variable'을 사용하셨습니까? – Rob
@Rob \t 'loopVariable'을 'Expression.Variable'으로 변경했지만 문제가 있습니다. –