Reputation: 49
I've googled but couldn't find satisfactory answers. I'm basically trying to get this code to work:
public List<WordEntry> WordDataBase = new List<WordEntry>();
public List<CharacterEntry> CharacterDataBase = new List<CharacterEntry>();
public List<Entry> SelectWhere<T>(System.Func<T, bool> predicate) where T : Entry
{
if (typeof(T) == typeof(WordEntry))
return WordDataBase.Where(predicate);
else if (typeof(T) == typeof(CharacterEntry))
return CharacterDataBase.Where(predicate);
else
return null;
}
In this sample, both WordEntry and CharacterEntry are derived from Entry. I get the compiler errors:
Error CS1503 Argument 2: cannot convert from 'System.Func<T, bool>' to 'System.Func<WordEntry, int, bool>'
and
Error CS1503 Argument 2: cannot convert from 'System.Func<T, bool>' to 'System.Func<CharacterEntry, int, bool>'
Hopefully you can help me with this. Thanks in advance
Upvotes: 2
Views: 4928
Reputation: 2836
From the errors you have shown i think your predicate has wrong declaration.
The where clause on both of your Database objects expects Func<T, int, bool>
, note the second argument which is int, so changing your extension method like this should be progress in the right direction
public List<Entry> SelectWhere<T>(Func<T, int, bool> predicate) where T : Entry
NOTE: You have declared generic method in which your code depends on the generic type, this makes to code somehow not so generic, check @Fabio answer i think he has point for creating the separate extension methods.
Upvotes: 0
Reputation: 1500535
Basically, you just need to cast - the language rules don't allow the compiler to take the if
statement into account when it thinks about the types involved. Note that you also need to call ToList<Entry>()
, specifying the type argument to avoid getting a List<WordEntry>
or List<CharacterEntry>
:
public List<Entry> SelectWhere<T>(Func<T, bool> predicate) where T : Entry
{
if (typeof(T) == typeof(WordEntry))
return WordDataBase
.Where((Func<WordEntry, bool>) predicate)
.ToList<Entry>();
else if (typeof(T) == typeof(CharacterEntry))
return CharacterDataBase
.Where((Func<CharacterEntry, bool>) predicate)
.ToList<Entry>();
else
return null;
}
I'd suggest that rather than making this generic though, you might want to just have two different methods instead. It doesn't feel like it's really a generic method, given that it only works with two very specific types.
Upvotes: 9
Reputation: 32445
Your method SelectWhere
does different things based on the type of argument - so why not just use overload methods
public List<WordEntry> SelectWhere(Func<WordEntry, bool> predicate)
{
return WordDataBase.Where(predicate);
}
public List<CharacterEntry> SelectWhere(Func<CharacterEntry, bool> predicate)
{
return CharacterDataBase.Where(predicate);
}
Then you can use those method without casting and "horrible" if...else
statements
Func<WordEntry, bool> isValid = word => word.SomeProperty > 0;
var filteredWords = SelectWhere(isValid); // WordDataBase will be used
Func<CharacterEntry, bool> IsValid = character => character.SomeProperty != null;
var filteredCharacters = SelectWhere(IsValid); //CharacterDataBase will be used
Upvotes: 4