0

I have a situation where I have a generic method which accepts an object of type generic and I want to write a LINQ query on that object.

Here is an example:

Generic Method:

public static void GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
      // How To Write LINQ Here to get non verified person      
}

Student Class:

public class Student
{
    public int Id { get; set; }

    public string Name { get; set; }

    public bool IsVerified { get; set; }
}

Teacher Class:

public class Teacher
{
    public int Id { get; set; }

    public string Name { get; set; }

    public bool IsVerified { get; set; }
}

Person Class:

public class Person<T>
{
    public List<T> PersonList { get; set; }
}

Main Class:

// 1. Get Non Verified Students
var persons = new Person<Student>();
var students = new List<Student>()
                    {
                        new Student { Id = 1, Name = "Student_A", IsVerified = true },
                        new Student { Id = 2, Name = "Student_B", IsVerified = false },
                    };
 persons.PersonList = new List<Student>();
persons.PersonList.AddRange(students);
GetNonNonVerifiedPersons(persons);


// 2. Get Non Verified Teachers
var persons2 = new Person<Teacher>();
var teachers = new List<Teacher>()
                    {
                        new Teacher { Id = 1, Name = "Teacher_A", IsVerified = true },
                        new Teacher { Id = 2, Name = "Teacher_B", IsVerified = false },
                        new Teacher { Id = 3, Name = "Teacher_C", IsVerified = false },
                    };
persons2.PersonList = new List<Teacher>();
persons2.PersonList.AddRange(teachers);
GetNonNonVerifiedPersons(persons2);
2
  • var result = persons.PersonList.Where(x => !x.IsVerified).ToList(); Commented Nov 18, 2015 at 5:13
  • @AbhilashPA: PersonList contains generic list. So it wont work. Commented Nov 18, 2015 at 5:50

2 Answers 2

4

You should use interface to be able to specify the type of Teacher and Student in generic type. When you use where clause compiler is able to do the type checks at compile time.

public interface IHuman
{  
    string Name { get; set; }
    bool IsVerified { get; set; }
}

public class Teacher : IHuman
{
    public int Id { get; set; }

    public string Name { get; set; }

    public bool IsVerified { get; set; }
}

public class Student : IHuman
{
    public int Id { get; set; }

    public string Name { get; set; }

    public bool IsVerified { get; set; }
}

And then your method should be like this. Here we have where clause that says only accept generic type TResult when implements IHuman.

public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model) where TResult : IHuman
{
    return model.PersonList.Where(x => !x.IsVerified);
}

Update : I highly suggest you to make the big changes because its how it should be.

Other way which is not common and extremely slow is to check for the types at runtime.

public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
    var list = model.PersonList;
    var t = list.FirstOrDefault() as Teacher;
    if (t != null)
    {
        return model.PersonList.Where(x => !(x as Teacher).IsVerified);
    }

    var s = list.FirstOrDefault() as Student;
    if (s != null)
    {
        return model.PersonList.Where(x => !(s as Student).IsVerified);
    }

    return null;
}
Sign up to request clarification or add additional context in comments.

5 Comments

You are right. But I am in a situation where i cannot use interface now. There will be a very big change.
@user2988458 see the update but note that you should use interface or a base class. because all your classes (Teacher and Student) have something in common. c# is object oriented language and you should use its power!
I highly appreciate your concern (+1 for that). But In question I have posted a sample example. In real world i have more than two classes which are having more than 20 properties and out of those properties only two properties are common. One is IsVerified and another is Name. :). So I guess using reflection is the only solution.
@user2988458 oh no problem man. just use IsVerified as common and only write that in interface. see i just removed one ;) . Only use the properties that are in common.
You can still use an interface for just those two properties. You can even implement multiple interfaces in a class if some of those other properties imply another interface.
1

May be this can do the trick:

IList<Person<TResult>> xyz = new List<Person<TResult>>();
var list = xyz.Where(a => a.GetType() == typeof(Student).IsVerified);

I didn't check it in IDE but something like this would work

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.