あなたがダイナミックプロパティを持つ本当にAnonymous Type
カウントを生成することはできませんので、あなたは、それがAnonymous Type
のためのコンパイラをやっている方法をカスタムタイプを生成する必要があります。
これは私がそれを使用したい方法です。このタイプを生成したら、渡された式の割り当てを簡単に設定してFieldSelector
にして、それをカスタムタイプに組み合わせることができます。あなたは以上の1つのレベルのネストclass1->class2->class3->Propery_1
でプロパティを取得しようとすると、ところで
public class FieldSelector<T>
{
private List<LambdaExpression> expressions;
public FieldSelector()
{
expressions = new List<LambdaExpression>();
}
public void Add(Expression<Func<T, object>> expr)
{
expressions.Add(expr);
}
public Expression<Func<T, object>> GetSelector()
{
// We will create a new type in runtime that looks like a AnonymousType
var str = $"<>f__AnonymousType0`{expressions.Count}";
// Create type builder
var assemblyName = Assembly.GetExecutingAssembly().GetName();
var modelBuilder = AppDomain.CurrentDomain
.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect)
.DefineDynamicModule("module");
var typeBuilder = modelBuilder.DefineType(str, TypeAttributes.Public | TypeAttributes.Class);
var types = new Type[expressions.Count];
var names = new List<string>[expressions.Count];
for (int i = 0; i < expressions.Count; i++)
{
// Retrive passed properties
var unExpr = expressions[i].Body as UnaryExpression;
var exp = unExpr == null ? expressions[i].Body as MemberExpression : unExpr.Operand as MemberExpression;
types[i] = exp.Type;
// Retrive a nested properties
names[i] = GetAllNestedMembersName(exp);
}
// Defined generic parameters for custom type
var genericParams = typeBuilder.DefineGenericParameters(types.Select((_, i) => $"PropType{i}").ToArray());
for (int i = 0; i < types.Length; i++)
{
typeBuilder.DefineField($"{string.Join("_", names[i])}", genericParams[i], FieldAttributes.Public);
}
// Create generic type by passed properties
var type = typeBuilder.CreateType();
var genericType = type.MakeGenericType(types);
ParameterExpression parameter = Expression.Parameter(typeof(T), "MyItem");
// Create nested properties
var assignments = genericType.GetFields().Select((prop, i) => Expression.Bind(prop, GetAllNestedMembers(parameter, names[i])));
return Expression.Lambda<Func<T, object>>(Expression.MemberInit(Expression.New(genericType.GetConstructors()[0]), assignments), parameter);
}
private Expression GetAllNestedMembers(Expression parameter, List<string> properties)
{
Expression expression = parameter;
for (int i = 0; i < properties.Count; ++i)
{
expression = Expression.Property(expression, properties[i]);
}
return expression;
}
private List<string> GetAllNestedMembersName(Expression arg)
{
var result = new List<string>();
var expression = arg as MemberExpression;
while (expression != null && expression.NodeType != ExpressionType.Parameter)
{
result.Insert(0, expression.Member.Name);
expression = expression.Expression as MemberExpression;
}
return result;
}
}
、あなたは現在のソリューション上記のコードで見たように例のために動作しません。それを修正するのは難しいことではありません。
編集:上記のケースが修正されました。今、あなたはclass1->class2->class3->Propery_1
をretriveことができ、それはそれの使い方です:
残念ながら
private class TestClass
{
public string Arg2 { get; set; }
public TestClass Nested { get; set; }
public int Id { get; set; }
}
var field = new FieldSelector<TestClass>();
field.Add(e => e.Arg2);
field.Add(e => e.Id);
field.Add(e => e.Nested.Id);
dynamic cusObj = field.GetSelector().Compile()(new TestClass { Arg2 = "asd", Id = 6, Nested = new TestClass { Id = 79 } });
Console.WriteLine(cusObj.Arg2);
Console.WriteLine(cusObj.Id);
Console.WriteLine(cusObj.Nested_Id);
、cusObjはコンパイルタイプでobject
なり、あなたはdynamic
としてそれをマークしていない場合、あなたは彼のpropertisを取得することはできません。あなたはリターンreturn query.Select(field.GetSelector()).ToListAsync()
希望、これは便利ですが呼び出されますときfield.GetSelector()
戻りFunc<T, object>
、あなたがTask<List<object>>
を取得するためところで
、あなたのpublic Task<List<T>> RunQuery<T>
は、コンパイルではないでしょう。
ありがとうございました!これはうまく動作します!私はdotnet coreを使用しているため、これを使用する必要があります:AssemblyBuilder.DefineDynamicAssembly – r03