'The type arguments cannot be inferred from the usage'
Solution 1
Well this is the problem:
public IEnumerable<IChromosome> Chromosomes
You're only declaring that you're returning a sequence of IChromosome
values. Your criterion expects MatchDay
values. You happen to know that it's actually returning a sequence of MatchDay
values, but the compiler doesn't.
You could use Cast<>
to check this at execution time:
return season.Chromosomes.Cast<U>().Count(Criteria);
... or you could change Chromosomes
to return an IEnumerable<MatchDay>
. Unfortunately we can't really tell whether that's a valid answer or not as we don't know how ICrossoverable
is declared. Perhaps you should make ICrossoverable
generic in the element type?
Solution 2
You should use keyword in
before U in CriteriaBase definition. Something like this:
public abstract class CriteriaBase<T, in U>
where T : ICrossoverable
where U : IChromosome
Update. It will not work. Try to specify type explicitly
private int GetNumberOfCriteriaMatches(T season)
{
....
return season.Chromosomes.Count<IChromosome>(Criteria);
}
Stuart Leyland-Cole
Updated on April 09, 2020Comments
-
Stuart Leyland-Cole about 4 years
I am having some troubles with generics and inheritance. I have an abstract class called
CriteriaBase
whose job it is to determine if an entityT
matches the criteria defined in any sub-classes. The sub-classes have to implement a method which returns aFunc
representing the criteria. The problem arises when I try to use generics for theFunc
. Hopefully some code will illustrate my problem.public abstract class CriteriaBase<T, U> where T : ICrossoverable where U : IChromosome { protected abstract Func<U, bool> Criteria { get; } //some code removed for brevity private int GetNumberOfCriteriaMatches(T season) { //1. works //Func<IChromosome, bool> predicate = c => c.Genes == null; //return season.Chromosomes.Count(predicate); //2. doesn't work - The type arguments for method 'int //System.Linq.Enumerable.Count<TSource>(this IEnumerable<TSource>, //Func<TSource, bool>)' //cannot be inferred from the usage. Try specifying the type arguments //explicitly. return season.Chromosomes.Count(Criteria); } }
My intention is that the
CriteriaBase
class should be generic and completely reusable.An example sub-class:
public class TopTeamsPlayingEachOtherCriteria : CriteriaBase<Season, MatchDay> { //some code removed for brevity protected override Func<MatchDay, bool> Criteria { get { return matchDay => matchDay.Fixtures.Count( fixture => fixture.HomeTeam.TableGrouping.Ordering == 1 && fixture.AwayTeam.TableGrouping.Ordering == 1) > 1; } } }
The problem is in the
GetNumberOfCriteriaMatches()
method. Option 2 is how I originally wrote the code but I get the compile error as listed. If I use option 1 then the code compiles but it means that when I overrideCriteria
in the sub-class, I have to useIChromosome
instead ofMatchDay
which doesn't work (I need to access specific features of aMatchDay
). In my simple mind, options 1 and 2 are equivalent. Option 2 simply replacesIChromosome
with a generic typeU
which is restricted to a class that implementsIChromosome
.Is what I'm trying to achieve possible? If so, what am I missing/misunderstanding? If not, how should I approach this problem?
For completeness (included at the end as I'm not sure how much it helps with the question), here are the two entities that I'm currently using for
T
(Season
) andU
(MatchDay
).public class Season : ICrossoverable { private readonly IEnumerable<MatchDay> _matchDays; public Season(IEnumerable<MatchDay> matchDays) { _matchDays = matchDays; } public IEnumerable<MatchDay> MatchDays { get { return _matchDays; } } //ICrossoverable implementation public IEnumerable<IChromosome> Chromosomes { get { return _matchDays; } } } public class MatchDay : IChromosome { private readonly int _week; private readonly List<Fixture> _fixtures; public MatchDay(int week, List<Fixture> fixtures) { _week = week; _fixtures = fixtures; } //some code removed for brevity public IEnumerable<Fixture> Fixtures { get { return _fixtures; } } //IChromosome implementation public IEnumerable<IGene> Genes { get { return Fixtures; } } }
-
Stuart Leyland-Cole about 11 yearsWhen I do this I get a compiler error saying 'Variant type parameters could be declared in interfaces or delegates only'. Three questions: what does adding
in
do, what does this error mean and why doesn't it work? Thanks! -
Kirill Bestemyanov about 11 yearsI forget that this could works only for delegates and interfaces. Ok. Than try to specify explicitly Count<IChromosome>(Criteria)
-
Stuart Leyland-Cole about 11 yearsNow have a different error! 'Argument type 'System.Func<U, bool>' is not assignable to parameter type 'System.Func<GeneticAlgorithm.IChromosome, bool>'. It's almost as if 'where U : IChromosome' doesn't exist! Where now?
-
Kirill Bestemyanov about 11 yearsI have no new ideas... Try to summon Jon Skeet here.
-
Stuart Leyland-Cole about 11 yearsAh ha! That clears it up. I think the actual solution lies in your last sentence - make
ICrossoverable
generic. I will try this tomorrow and report back. -
Stuart Leyland-Cole about 11 yearsAs suggested, I made
ICrossoverable
generic which solved my problem. The code is in my Github repository. I renamed ICrossoverable to IOrganism as it fits much better with the genetic algorithm terminology. An implementation of `CriteriaBase<TOrganism, TChromosome> can be found in another Github repository. Thanks for the multiple and varied suggestions.