views:

218

answers:

5

Consider the following classes:

class TypeA;
class TypeB : TypeA;
class TypeC : TypeA;
class TypeD : TypeA;

and the following List<> types:

List<TypeB> listTypeB;
List<TypeC> listTypeC;
List<TypeD> listTypeD;

Now TypeA has a property Prop1 of type Object1 and I want to locate which list has stored within it an item with Prop1 of a given value. Is there a way in which I can do something like the following, so that I only need to write the search code once?

bool LocateInAnyList(Object1 findObj)
{
  bool found = false;

  found = ContainsProp1(findObj, listTypeB);
  if(!found)
  {
    found = ContainsProp1(findObj, listTypeC);
  }
  if(!found)
  {
    found = ContainsProp1(findObj, listTypeD);
  }
  return found;
}


bool ContainsProp1(Object1 searchFor, List<TypeA> listToSearch)
{
   bool found = false;

   for(int i = 0; (i < listToSearch.Count) & !found; i++)
   {
      found = listToSearch[i].Prop1 == searchFor;
   }
   return found;
}
A: 

You won't really be able to do this in this way until C# 4.0 comes out because of the added variance/covariance support.

You can hack it for now by allowing the user to pass in IEnumerable, and just looping over that while casting the object to TypeA

bool ContainsProp1(Object1 searchFor, IEnumerable listToSearch)
{
   bool found = false;

   foreach(object obj in listToSearch)
   {
      found = ((TypeA)obj).Prop1 == searchFor;
      if (found) break;
   }
   return found;
}
Joel Martinez
Covariance is unnecessary for this scenario.
mquander
+5  A: 

Yes. You'll need to make the "contains" method generic, with a constraint so that you can operate only on objects that derive from TypeA (and thus have a Prop1:)

bool ContainsProp1<T>(Object1 searchFor, List<T> listToSearch) where T : TypeA
{
   bool found = false;

   for(int i = 0; (i < listToSearch.Count) & !found; i++)
   {
      found = listToSearch[i].Prop1 == searchFor;
   }
   return found;
}

Your first method should then compile as-is.

mquander
Are you sure that compiles like that?
Chris Dunaway
I removed my extra typoed colon; other than that, yeah, looks fine to me.
mquander
Close - unfortunately ybo syntax was correct for the function definition, but have +1 anyway.
ChrisBD
When I paste that code as is, the IDE highlights the 'where' keyword with the following error: "Constraints are not allowed on non-generic declarations"To fix it I had to change it to this:bool ContainsProp1<T>(Object1 searchFor, List<T> listToSearch) where T : TypeA {...}
Chris Dunaway
Sorry, that's correct. I edited my answer.
mquander
+3  A: 

You can use generic

bool ContainsProp1<T>(Object1 searchFor, List<T> listToSearch) where T : TypeA
{
   bool found = false;

   for(int i = 0; (i < listToSearch.Count) & !found; i++)
   {
      found = listToSearch[i].Prop1 == searchFor;
   }
   return found;
}

If you can use linq, your code can be more clear than that.

ybo
Thank you that works fine.
ChrisBD
+1  A: 

You could do something like this (using lambdas & generics & nice things like that):

public bool LocateInAnyList(Object1 obj)
{
    return SearchList(listTypeB, obj) || SearchList(listTypeC, obj) || SearchList(listTypeD, obj);
}

private static bool SearchList<T>(List<T> list, Object1 obj) where T : TypeA
{
    return list.Exists(item => item.Prop1 == obj);
}
thecoop
Personally, I'd say this should be the accepted answer. It is fairly well documented that these delegate based methods are faster than iterating through the list by hand. Plus it's a lot more elegant.
MPritch
A: 

Yes. First, you can make the method generic, by changing its signature like the following:

bool ContainsProp(Object searchFor, List<T> listToSearch) : where T : TypeA {}

this will allow you to pass any of the lists you have.

Second, I would change the second parameter to receive an array of lists:

bool ContainsProp<T>(Object searchFor, List<T> [] listsToSearch) where T : TypeA {}

This way, you could pass all the lists at once:

found = ContainsProp(objToSearch, listA, listB, listC);
Eduardo Scoz
have you even checked your examples compile?
MPritch
Yes. It doesn't compile because I'm not showing the entire implementation, just the method signature, like I mention in the first line.
Eduardo Scoz