Chris
Chris

Reputation: 6760

Downcasting and Linq

I have a base class called LabFileBase. I have constructed a List and have added my derived classes to it. I want to search the List for a particular object based on a key I've defined. The problem I'm having is how do you downcast in a LINQ expression?

Here is some sample code:

public abstract class LabFileBase
{
}

public class Sample1 : LabFileBase
{    
    public string ID {get;set;}
    public string Name {get;set;}
    //..
}

public class Sample2 : LabFileBase
{    
    public string ID {get;set;}
    public string Name {get;set;}
    //..
}

I want to search for a particular Sample2 type, but I need to downcast if i used a regular foreach loop like this:

foreach(var s in processedFiles)  //processedFiles is a List<LabFileBase>
     if (s is Sample2)
         var found = s as Sample2;
             if (found.ID = ID && found.Name == "Thing I'm looking for")
                  //do extra work

I would much rather have something like this:

var result = processedFiles.Select(s => s.ID == SomeID && s.Name == SomeName);

Is this possible and what syntactic punctuation is involved, or is the foreach my only option because of the different objects. Sample1 and Sample2 only have ID and Name as the same fields.

EDIT: Thanks to all for your support and suggestions, I've entered almost everything into the backlog to implement.

Upvotes: 1

Views: 1121

Answers (3)

Ian Suttle
Ian Suttle

Reputation: 3402

Interesting question. In addition to Jon Skeet's (which is better than this option) note you could try a more manual alternative. Add an additional property containing an identifier for the type of object it is.

public abstract class LabFileBase
{
    public string LabFileObjectType { get; }
    public string ID {get;set;}
    public string Name {get;set;}
}


public class Sample1 : LabFileBase
{    
    public string LabFileObjectType { get { return "Sample1"; } }
    //..
}

public class Sample2 : LabFileBase
{    
    public string LabFileObjectType { get { return "Sample2"; } }
    //..
}

Then you could query against that property as well:

var result = processedFiles.Select(s => s.ID == SomeID && s.Name == SomeName && s.LabFileObjectType == "Sample2");

Upvotes: 0

mqp
mqp

Reputation: 71937

To elaborate on Jon's answer, OfType is almost certainly the correct operator if you aren't willing to put these fields into your base class. For example:

foreach(var s in processedFiles.OfType<Sample2>())
    if(s.ID == ID && s.Name == "Thing I'm looking for")
        // whatever

foreach(var s in processedFiles.OfType<Sample1>())
    if(s.ID == ID && s.Name == "Some other thing")
        // and so on

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1500105

Why not put ID and Name into the base class? Then you don't need any downcasting.

If you do need casting though, the Cast and OfType operators may be helpful to you. Each transforms a sequence into a sequence of the specified type: Cast assumes that each element is the right type (and throws an exception if that's not the case); OfType works more like the C# as operator, only returning elements which happen to be the right type and ignoring others.

Upvotes: 6

Related Questions