Konversi pohon Ekspresi

biarkan disana ada :

Expression<Func<Message, bool>> exp1 = x => x.mesID == 1;
Expression<Func<MessageDTO, bool>> exp2 = x => x.mesID == 1;

sekarang saya harus meneruskan exp1 ke _db.Messages.where(exp1); masalahnya adalah saya hanya punya exp2, saya perlu mengonversi tipenya menjadi Pesan, Semua propertinya sama!

sekarang saya melakukan ini:

  var par = Expression.Parameter(typeof(Message));
  var ex = (Expression<Func<Message, bool>>)Expression.Lambda(exp2.Body, par);

Masalah dengan ini adalah parameter input diubah ya! tetapi x di dalam badan lambda "x.mesID" adalah tipe lama.

Adakah cara untuk mengubah semua jenis parameter di badan juga atau mengubah parameter masukan yang mencerminkan badan juga?

Saya kira ini adalah masalah besar yang selalu saya alami dengan LINQ, karena antar lapisan saya tidak dapat meneruskan kelas yang dihasilkan, karena ini akan membuat lapisan digabungkan, jadi saya harus membuat kelas yang ringan, sekarang bagaimana cara menggunakan metode seperti _db.Messages .Di mana(); dari lapisan bisnis?!! sementara lapisan bisnis tidak mengetahui apa pun tentang jenis Pesan, ia hanya mengetahui MessageDTO.


person Stacker    schedule 08.09.2010    source sumber


Jawaban (1)


Tidak, pada dasarnya. Pohon ekspresi tidak dapat diubah, dan berisi metadata anggota penuh (yaitu mesID adalah messageDTO.mesID). Untuk melakukan ini, Anda harus membangun kembali pohon ekspresi dari awal (melalui pengunjung), menangani setiap tipe node yang perlu Anda dukung.

Jika pohon ekspresi dasar ini seharusnya baik-baik saja, tetapi apakah Anda perlu mendukung keseluruhan keseluruhan? PITA yang sangat besar (terutama di .NET 4, yang menambahkan lebih banyak tipe node).


Contoh dasar yang hanya diperlukan untuk contoh tersebut; Anda perlu menambahkan lebih banyak tipe simpul untuk ekspresi yang lebih kompleks:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
static class Program
{
    static void Main()
    {
        Expression<Func<Message, bool>> exp1 = x => x.mesID == 1;
        var exp2 = Convert<Message, MessageDTO>(exp1);
    }
    static Expression<Func<TTo, bool>> Convert<TFrom, TTo>(Expression<Func<TFrom, bool>> expr)
    {
        Dictionary<Expression,Expression> substitutues = new Dictionary<Expression,Expression>();
        var oldParam = expr.Parameters[0];
        var newParam = Expression.Parameter(typeof(TTo), oldParam.Name);
        substitutues.Add(oldParam, newParam);
        Expression body = ConvertNode(expr.Body, substitutues);
        return Expression.Lambda<Func<TTo,bool>>(body, newParam);
    }
    static Expression ConvertNode(Expression node, IDictionary<Expression, Expression> subst)
    {
        if (node == null) return null;
        if (subst.ContainsKey(node)) return subst[node];

        switch (node.NodeType)
        {
            case ExpressionType.Constant:
                return node;
            case ExpressionType.MemberAccess:
                {
                    var me = (MemberExpression)node;
                    var newNode = ConvertNode(me.Expression, subst);
                    return Expression.MakeMemberAccess(newNode, newNode.Type.GetMember(me.Member.Name).Single());
                }
            case ExpressionType.Equal: /* will probably work for a range of common binary-expressions */
                {
                    var be = (BinaryExpression)node;
                    return Expression.MakeBinary(be.NodeType, ConvertNode(be.Left, subst), ConvertNode(be.Right, subst), be.IsLiftedToNull, be.Method);
                }
            default:
                throw new NotSupportedException(node.NodeType.ToString());
        }
    }
}
class Message { public int mesID { get; set; } }
class MessageDTO { public int mesID { get; set; } }
person Marc Gravell    schedule 08.09.2010
comment
apa maksudnya lewat vistor? bisakah Anda memberi saya contoh? - person Stacker; 08.09.2010
comment
Implementasi pengunjung; yaitu beberapa konstruksi kode yang Anda gunakan untuk melintasi seluruh struktur pohon, biasanya membangun pohon alternatif (dari simpul daun kembali ke akar, karena setiap cabang tidak dapat diubah). Ini mungkin bermuara pada sebuah saklar besar (pada tipe node), dengan penanganan rekursif untuk setiap tipe node. Saya akan mencoba memberikan contoh... - person Marc Gravell; 08.09.2010
comment
terima kasih Marc, ini berhasil, saya hanya perlu membuatnya mendukung lebih banyak ExpressionType - person Stacker; 08.09.2010
comment
@Stacker - itulah bagian yang menyenangkan ;p Perhatikan bahwa Anda harus dapat menggunakan kembali potongan besar; misalnya sebagian besar ekspresi biner harus dapat menggunakan contoh yang ada. - person Marc Gravell; 08.09.2010
comment
hanya satu pertanyaan yang aku punya untukmu. bagaimana Anda menangani kasus ExpressionType.Convert: - person Stacker; 15.09.2010
comment
@MarcGravell apakah Anda juga tahu tentang ExpressionType.New? - person Vahid Farahmandian; 14.04.2019