简体   繁体   中英

How to dynamically create an Expression<Func<T, object>>

I have a class like this:

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string LOANIDBPM { get; set; }
    public string REPORTTYPE { get; set; }
}

I have a list Students, I want to filter some student in list by LOANIDBPM and REPORTTYPE .

Usually, this is the code (using linq)

public void GetListStudent(List<Student> listStudent)
{
    listStudent = listStudent.Where(x => x.LOANIDBPM == "MIKEN" && x.REPORTTYPE == "DX").ToList();
}

However, for some reason, i can't Explicit "List", My solution is below:

public void GetListStudent(object[] listStudent)
{
    ParameterExpression param = Expression.Parameter(listStudent.First().GetType(), nameof(listStudent));
    Expression propLoanBPM = Expression.Property(param, "LOANIDBPM");
    Expression<Func<string>> loanIdLampda = () => "MIKEN";
    Expression searchLoanBPM = Expression.Equal(propLoanBPM, loanIdLampda.Body);

    Expression propReportType = Expression.Property(param, "REPORTTYPE");
    Expression<Func<string>> reportTypeLampda = () => "DX";

    Expression searchReportType = Expression.Equal(propReportType, reportTypeLampda.Body);

    Expression searchFinal = Expression.And(searchLoanBPM, searchReportType);


    Expression<Func<???, bool>> lampda = Expression.Lambda<Func<???, bool>>(searchFinal, param);

    listStudent = listStudent.Where(lampda).ToArray();
}

The code above has two problems:

1: I don't know type of Student in Expression Func, I can't use like:

Expression<Func< listStudent.First().GetType(), bool>> lampda = Expression.Lambda<Func< listStudent.First().GetType(), bool>>(searchFinal, param);

2: In Where method, it's need to IQueryable , but in my code is Expression Func.

Sorry by my English. Thank you so much

Your first example doesn't compile because listStudent is a list and LINQ is generally going to return an IEnumerable of some kind. You need to add ToList() :

public void GetListStudent(List<Student> listStudent)
{
    listStudent = listStudent
        .Where
        (
            x => x.LOANIDBPM == "MIKEN" && x.REPORTTYPE == "DX"
        )
        .ToList();  //<-- add this
}

Your second example doesn't work because c# doesn't know that your object array is actually a list of students. You can tell it using the Cast<>() method. When you're done, you need to convert back to an array, so add ToArray() at the end.

public void GetListStudent(object[] listStudent)
{
    listStudent = listStudent
        .Cast<Student>()  //<-- add this
        .Where
        (
            x => x.LOANIDBPM == "MIKEN" && x.REPORTTYPE == "DX"
        )
        .ToArray();       //<-- and this
}

If only some of the objects are known to be students, you can use OfType<>() to filter them out.

public void GetListStudent(object[] listStudent)
{
    listStudent = listStudent
        .OfType<Student>()  //<-- add this
        .Where
        (
            x => x.LOANIDBPM == "MIKEN" && x.REPORTTYPE == "DX"
        )
        .ToArray();       //<-- and this
}

And if you have absolutely no clue what those objects are but are quite certain they have LOANIDBPM and REPORTTYPE properties, I suppose you could use dynamic :

public void GetListStudent(List<dynamic> listStudent)
{
    listStudent = listStudent
        .Where
        (
            x => x.LOANIDBPM == "MIKEN" && x.REPORTTYPE == "DX"
        )
        .ToList();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM