Sinaesthetic
Sinaesthetic

Reputation: 12192

How do I return all items in a collection that possess an interface property of a specific type?

I have a class ApprovalTicket that has a property called ApprovalRules that is of type IApproval:

IApproval ApprovalRules;

This field will contain several different types of classes that implement that interface. Now stepping one level up, I will have a List of ApprovalTickets. What I'm trying to do is use linq to return a list of ApprovalTickets that have ApprovalRules of the type MocReviewerApproval.

I was trying something like:

var reviews = request.MocApprovalTasks
  .Where(mocApproval => mocApproval.ApprovalRules is MocReviewerApproval)
  .ToList();

But when I check the list that gets returned, it's still including tickets that have an ApprovalRules type of MocManagerApproval and others as well. What am I missing?

UPDATE:

Let me be more specific. Here is the inheritance scheme

MocApproval : TaskTicket
    >>IApproval ApprovalRules;

MocReviewerApproval : IApproval
MocManagerApproval : IApproval
MocControllerApproval : IApproval


    internal interface IApproval
    {
        bool Approve(Guid approverGuid, MocApproval approval);
        bool Deny(Guid approverGuid, MocApproval approval, TaskComment denialComment);
        bool Close(Guid approverGuid, MocApproval approval, TaskComment closeComment);
        bool Notify();
        void Set(MocApproval approval);
        User GetAssignee();
        TaskComment GetNotificationComment();
    }

Upvotes: 0

Views: 78

Answers (2)

Servy
Servy

Reputation: 203842

is means, can be validly cast to, not, "is exactly this type". In your case, any sub-classes of MocReviewerApproval will still return true. You can use:

 mocApproval.ApprovalRules.GetType() == typeof(MocReviewerApproval)

to ensure that that type, and only that type, will return true. Having said that, it's kinda bad code smell to have something like this. Consider asking yourself if that's really what you want.

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500825

Your code looks fine to me. I suspect you've got diagnostic problems, or you're not after the is kind of relationship at all. Here's a complete example showing it working:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Foo
{
    public object Value { get; set; }
}

class Test
{
    static void Main()
    {
        var list = new List<Foo>
        {
            new Foo { Value = "" },
            new Foo { Value = 10 },
            new Foo { Value = new object() },
            new Foo { Value = new MemoryStream() }
        };

        ShowCount<IDisposable>(list); // 1 (MemoryStream)
        ShowCount<IFormattable>(list); // 1 (Int32)
        ShowCount<IComparable>(list); // 1 (String, Int32)
    }

    static void ShowCount<T>(List<Foo> list)
    {
        var matches = list.Where(f => f.Value is T)
                          .ToList();
        Console.WriteLine("{0} matches for {1}", 
                          matches.Count, typeof(T));
    }
}

EDIT: If you want matches which are exactly the given type, use:

var reviews = request.MocApprovalTasks
                     .Where(task => task.ApprovalRules.GetType() == 
                                           typeof(MocReviewerApproval))
                     .ToList();

That's more refactoring-friendly than finding the name as per Servy's original answer.

Upvotes: 1

Related Questions