1

ここで見つけた匿名型の新しいシーケンスにシーケンスを射影する LINQ 式を作成しましたLINQ expression tree with anonymous types

実行したい式は次のとおりです。

Document doc = ....;
doc.AllStatements.Select(s => new { field = s.Amount });

これは括弧内のセレクターの実行時の表現です:

{t => new field;Decimal;() {field = t.Amount}}

そして、これは式全体の実行時表現です。

{System.Linq.Enumerable+<UnionIterator>d__88`1[SISTEM.Models.Statement].Select(t => new field;Decimal;() {field = t.Amount})}

デバッグ中に列挙しようとすると、次のようになります。

") expected"

このように複数のフィールドの匿名型を試してみると:

doc.AllStatements.Select(s => new { field = s.Amount, field2 = s.Account });

私はこれを得る:

{System.Linq.Enumerable+<UnionIterator>d__88`1[SISTEM.Models.Statement].Select(t => new field;Decimal;field1;Nullable`1;() {field = t.Amount, field1 = t.Account})}

実行時エラーは次のとおりです。

"Unexpected character '`'"

誰かがこれを解読するのを手伝ってくれますか?

アップデート:

これは私の実際の呼び出しです:

var res = Expressions.DoExpression(typeof(Document), doc, "AllStatements.Select(new field=Amount, field1=Account)");

ただし、DoExpressions 関数の背後には多くの解析式と LINQ 式があります (500 行程度のコード)。

更新 2:

まず、コードのスニペットを次に示します。

Dokument doc = db.Dokumenti.First(); // Proper document, entity object;
var res = Expressions.DoExpression(
    typeof(Dokument), 
    doc, 
    "SviFinStavovi.Select(new id=Iznos, dsc=Opis)"
);

SviFinStavovi は Dokument のナビゲーション プロパティであり、Iznos と Opis は SviFinStavovi の基になる型のプロパティです。

ただし、これらの 2 行のコードは例外をスローしません。res を列挙しようとした場合にのみ、例外がスローされます。あなたは上記のものを持っています。

SviFinStavovi.Select(Iznos) を入れていれば、問題なく動作したはずです。

これは DoExpression です:

public static object DoExpression(Type t, object obj, string expression){
ParameterExpression pe = Expression.Parameter(obj.GetType(), "objekat");
Expression SelectExpr = Expressions.ResolveCompleteExpression(pe, expression.Prepare());
return Expression.Lambda(SelectExpr, pe).Compile().DynamicInvoke(obj);}

ResolveCompleteExpression は全体を解析します。

さて、これは私がこのサイト、上記のリンクから取得した機能であり、追加したものであり、問​​題を引き起こします。

    public static Expression SelectDynamic(Expression expr, IEnumerable<string> fieldNames)
    {
        Type source = expr.Type.GetGenericArguments()[0];
        Dictionary<string, PropertyInfo> sourceProperties = new Dictionary<string, PropertyInfo>();
        foreach (string arg in fieldNames) sourceProperties.Add(arg.Split('=')[0].Trim(), source.GetProperty(arg.Split('=')[1].Trim()));                       
        Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicTypeWrapper(sourceProperties);

        ParameterExpression sourceItem = Expression.Parameter(source, "t");
        IEnumerable<MemberBinding> bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, Expression.Property(sourceItem, sourceProperties[p.Name]))).OfType<MemberBinding>();
        Expression selector = Expression.Lambda(Expression.MemberInit(
            Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem);
        return Expression.Call(typeof(Queryable), "Select", new Type[] { source, dynamicType }, expr, selector);
    }

この時点で、expr は (正しく) doc.SviFinStavovi を表し、フィールド名は ["id=Iznos"] ["dsc=Opis"] になります。

さて、これは私のコードではありません。私に合わせて少し調整しただけです。これは、上記のスニペットの実質的に最後に実行されたコード行です。スタックを巻き戻してコンパイルするだけです。

これが意味をなさない場合は申し訳ありません。説明が必要な場合は、お尋ねください。

4

2 に答える 2

0

selectには、newの後のフィールドを括弧で囲む必要があると思います。

 Select("new(<property1>,<property2>,...)");


var res = Expressions.DoExpression(typeof(Document), doc, "AllStatements.Select(new (field=Amount, field1=Account))");
于 2012-09-17T16:01:50.520 に答える
0

匿名のプロジェクションを作成することはできませんでしたが、小さなクラスとプロジェクトを作成しました。

public class LookupModel
{
    public LookupModel(int id, string dsc)
    {
        ID = id;
        DSC = dsc;
    }

    public int ID { get; set; }
    public string DSC { get; set; }
}

だからこれを使って:

function LINQSelectNew(Expression expr, string[] args)
{
Type type = expr.Type.GetGenericArguments()[0];
ParameterExpression parameter = Expression.Parameter(type, type.Name);

List<Expression> lista = new List<Expression>();                    
foreach (string s in args) lista.Add(Expressions.ResolveCompleteExpression(parameter, s.Prepare()));

Expression New = Expression.New(typeof(LookupModel).GetConstructor(lista.Select(e => e.Type).ToArray()), lista.ToArray());

return Expression.Call(
    typeof(Queryable),
    "Select",
    new Type[] { type, New.Type },
    expr,
    Expression.Lambda(New, new ParameterExpression[] { parameter }));
}

私がすることができます:

var res = Expressions.DoExpression(
    typeof(Dokument), 
    doc, 
    "SviFinStavovi.Select(new LookupModel(amount, amount.ToString()))"
);

これが誰かに役立つことを願っています...

于 2012-09-17T18:29:15.473 に答える