clD
clD

Reputation: 2611

Generic method to count occurances of a given SubClass in a List and why the Type parameter is not found

I have a List<Doctor> doctors where Doctor is an abstract class.

In the list I have SubClasses such as DoctorJunior, DoctorSenior etc.

How can I count the number of occurrences of a particular SubClass.

This works int count = doctors.Count(c => c is DoctorJunior);

however when I place it in a method using Type as a parameter it does not work.

public int GetOccurences(Type doctorType)
{
    // return Passengers.OfType<doctorType>().Count();

    // return doctors.Count(c => c is doctorType)

    int count = 0;
    foreach (Doctor doc in Doctors)
    {
        if (doc is doctorType)
        {
            count++;
        }
    }
    return count;
}

The parameter doctorType cannot be found.

Why is the parameter doctorType not found and how can I make a generic method to count types?

Thanks

Upvotes: 2

Views: 660

Answers (3)

Fabjan
Fabjan

Reputation: 13676

The reason why it's not working is that is operator is used only when you compare instance of type with type itself. You can use doc.GetType() instead and compare this type with type that is stored in doctorType :

public int GetOccurences(Type doctorType)
{
    int count = 0;
    foreach (Doctor doc in Doctors)
        if (doc.GetType() == doctorType) count++;

    return count;
}

Or use LINQ :

public int GetOccurences(Type doctorType)
{
    return Doctors.Count(d => d.GetType() == doctorType);
}

You can even use Convert.ChangeType(obj, type); to count however it's not recommended :

    static int GetOccurences(IEnumerable<object> collection, Type t)
    {
        return collection.Count(item => { try { Convert.ChangeType(item, t); return true; } catch { return false; } });
    }

Or Generic approach :

    static int GetOccurences<T>(IEnumerable<object> collection)
    {
        return collection.Count(item => item is T);
    }

P.S.

It worth noting that your custom class such as DoctorJunior is type (defined by You) but not a System.Type.

System.Type is a class that works with types.

A. Correct

if(c is DoctorJunior) ...
  • We use is operator here with class instance on the left side and class name on the right (not instance of class System.Type)

B. Incorrect

Type t = typeof(DoctorJunior);
if(c is t) ...
  • We attempt to compare instance of class with instance of System.Type using is operator. This is not valid since is operator doesn't work this way. It only allows to compare instance of class on left side and type name on right for example if(myVariable is Int32 / string / MyClass / ...)

Upvotes: 2

Igor Bendrup
Igor Bendrup

Reputation: 2837

Operator is doesn't expect variable of type System.Type on the right side. So, you get an exception. Valid using of is operator in your case only can be something like doc is DoctorJunior

To make your method work, you can use following code:

public int GetOccurences(Type doctorType)
{
    return doctors.Count(c => c.GetType() == doctorType);
}

Upvotes: 0

Jamiec
Jamiec

Reputation: 136134

You could make it a generic method, whereby generic constraints could give you some additional type safety (constrain the type argument to subclasses of Doctor)

public int GetOccurences<TDoctor>() where TDoctor:Doctor 
{
    ...
    if (doc is TDoctor)
    ...
}

Incidentally, this works well with your both your commented out lines

return Passengers.OfType<TDoctor>().Count();
// or
return doctors.Count(c => c is TDoctor);

or stick with what you've got and use GetType() (but there is no type safety, I could easily pass typeof(int), for example)

public int GetOccurences(Type doctorType)
{
    ...
    if (doc.GetType() == doctorType)
    ...
}

Upvotes: 0

Related Questions