简体   繁体   中英

Pass property name as parameter

I have the following class

public class School
{
    public List<Student> Students { get; set; }
    public List<Teacher> Teachers { get; set; }
}

Now i have this method

public bool Evaluate(??)
{
    var school = DbContext.Schools.FirstOrDefault();
    return school.??.Any(/*some expresions*/)
}

I should be able to pass a value in ?? and use it so that i can use both

return school.Students.Any(/*some expresions*/)
return school.Teachers.Any(/*some expresions*/)

So how can i replace the question marks with Students or Teachers ?

Edit:

public class Student 
{
    public string FullName { get; set; }
    public bool Registered { get; set; }
    public bool Passed { get; set; }
}

public class Teacher
{
    public string FullName { get; set; }
    public bool CanEvaluate { get; set; }
    public bool Validator { get; set; }
}


public class DynamicCheckTest
{
    public bool MyExpression<T>(List<T> items, string name,
        Expression<Func<T, bool>> expression)
    {
        return items.Any(x => expression.Compile()(x));
    }
}

public static bool Check<T>(this List<T> items, Func<T, bool> compiledExp)
{
    return items.Any(x => compiledExp(x));
}

Students.Check(x => x.Name == "Mike" &&  x.Registered); // example
Teachers.Check(x => x.Name == "Jack" &&  x.CanEvaluate);// example

Now i have to pass the school along which contains both Students and Teachers But i don't know which one will be called in advance

Addressing the "Pass property name as parameter" request, you could use reflection for that, but I don't think that's a good way to go. Instead, a Func<School, List<TElement>> could be used to select the desired List<> property to evaluate...

public bool Evaluate<TElement>(Func<School, List<TElement>> listSelector)
    where TElement : Person
{
    School school = DbContext.Schools.FirstOrDefault();
    DateTime today = DateTime.Today;

    return listSelector(school)
        // For example, check if today is the birthday of anyone in the selected list
        .Any(person => person.DateOfBirth.Month == today.Month && person.DateOfBirth.Day == today.Day);
}

As @Enigmativity points out, the type constraint is necessary in order to pass much of a meaningful condition to Any() , which also assumes/requires that Student and Teacher have common ancestry, like this...

public abstract class Person
{
    public DateTime DateOfBirth
    {
        get;
    }
}

public class Student : Person
{
}

public class Teacher : Person
{
}

You'd then use a lambda expression to specify the desired List<> ...

bool isAnyStudentsBirthday = Evaluate(school => school.Students);
bool isAnyTeachersBirthday = Evaluate(school => school.Teachers);

This will work as long as the members you want Any() to consider are available in the constrained type (ie Person ). If you wanted to filter using members specific to the Student or Teacher class, your best bet would be to use an approach like @Enigmativity's answer , where the filter itself is a parameter and receives the same derived type as the selected List<> stores.

Note that if you ever want to use Evaluate() with some other collection property of School that is not specifically List<> , or just knowing that all Any() needs is an IEnumerable<> , you could change the return type (last type parameter ) of the Func<> to something less-restrictive...

Func<School, IList<TElement>>
Func<School, ICollection<TElement>>
Func<School, IEnumerable<TElement>>

You could use this method:

public bool Evaluate<T>(Func<School, List<T>> project, Func<T, bool> filter)
{
    var school = DbContext.Schools.FirstOrDefault();
    return project(school).Any(filter);
}

If we assume that the implementation of Student and Teacher are this:

public class Student
{
    public string Name;
}

public class Teacher
{
    public string Subject;
}

Then you could do this:

bool hasFred = Evaluate(school => school.Students, student => student.Name == "Fred Nerk");
bool teachArt = Evaluate(school => school.Teachers, teacher => teacher.Subject == "Art");

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