我需要在运行时使用linq到对象连接不同的数据源,但我的数据源类型是未知的。所以,我不能直接使用Join。 我有一个包含我的数据源的字典,这就是我得到了多远:
public virtual IEnumerable DataSource { get; set; }
public virtual void MergeDataSources()
{
var outerType = System.Type.GetType(DataSources.Keys.First());
DataSource = Cast(DataSources[DataSources.Keys.First()], outerType);
foreach (var typeName in DataSources.Keys.Skip(1))
outerType = Join(outerType, System.Type.GetType(typeName), new[] { "CodigoCliente" }, new[] { "CodigoCliente" });
}
private IEnumerable Cast(IEnumerable datasource, Type type)
{
return typeof(Enumerable)
.GetMethod("Cast")
.MakeGenericMethod(type)
.Invoke(null, new object[] { datasource }) as IEnumerable;
}
private Type Join(Type outerType, Type innerType, string[] outerKey, string[] innerKey)
{
var outerKeySelector = GetKeySelector(outerType, outerKey);
var innerKeySelector = GetKeySelector(innerType, innerKey);
var resultSelector = Expression.Lambda(
null, // <<<<<<------- MISSING!!!
Expression.Parameter(outerType),
Expression.Parameter(innerType));
DataSource = typeof(Enumerable)
.GetMethod("Join")
.MakeGenericMethod(outerType, innerType, typeof(string), typeof(IEnumerable))
.Invoke(null, new object[] { DataSource, DataSources[innerType.AssemblyQualifiedName], outerKeySelector, innerKeySelector, resultSelector }) as IEnumerable;
return null; // <<<<<<------- MISSING!!!
}
我需要的最后一件事是:每个连接的类型必须是结果对象的属性。示例:new {Type1 = some_Obj_Of_Type1,Type2 = some_Obj_Of_Type2}
编辑: 我添加了一个DataSource属性,它表示我的合并集合
答案 0 :(得分:1)
您可以使用Reflection.Emit
动态创建返回类型,请查看此处 - How to create LINQ Expression Tree with anonymous type in it。
符合您的示例:
private Type Join(Type outerType, Type innerType, string[] outerKey, string[] innerKey)
{
var outerKeySelector = GetKeySelector(outerType, outerKey);
var innerKeySelector = GetKeySelector(innerType, innerKey);
Dictionary<string, Type> dynamicFields = new Dictionary<string, Type>
{
{ outerType.Name, outerType },
{ innerType.Name, innerType }
};
Dictionary<string, ParameterExpression> parameters = new Dictionary<string, ParameterExpression>
{
{ outerType.Name, Expression.Parameter(outerType) },
{ innerType.Name, Expression.Parameter(innerType) }
};
Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(dynamicFields);
var resultSelector = Expression.Lambda(
Expression.MemberInit(
Expression.New(
dynamicType.GetConstructor(Type.EmptyTypes)),
dynamicType.GetFields().Select(f => Expression.Bind(f, parameters[f.Name]))),
parameters.Values)
.Compile();
DataSource = typeof(Enumerable)
.GetMethods().Where(m => m.Name == "Join" && m.GetParameters().Length == 5).First()
.MakeGenericMethod(outerType, innerType, typeof(string), typeof(object))
.Invoke(null, new object[] { DataSource, DataSources[innerType.AssemblyQualifiedName], outerKeySelector, innerKeySelector, resultSelector }) as IEnumerable;
return dynamicType;
}