Reputation: 6760
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
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
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
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