2013-04-07 47 views
6

kullanımından çıkarılamıyor. Bazı jenerik ve miras sorunları yaşıyorum. İşi T öğesinin herhangi bir alt sınıfta tanımlanan ölçütlerle eşleşip eşleşmediğini belirlemek olan CriteriaBase adlı bir özet sınıfım var. Alt-sınıflar, kriterleri temsil eden bir Func döndüren bir metodu uygulamak zorundadır. Sorun, Func için jenerik kullanmayı denediğimde ortaya çıkar. Umarım bazı kodlar benim sorunumu gösterir.'Tür argümanları'

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); 
    } 
} 

Niyetim CriteriaBase sınıf jenerik ve tamamen tekrar olması gerektiğidir.

bir örneği, bir alt-grubu:

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; } 
    } 
} 

sorun GetNumberOfCriteriaMatches() yöntemindedir. Seçenek 2, kodu ilk olarak yazdım ancak listelenen derleme hatasını alıyorum. Seçenek 1'i kullanırsam, kod derler ama alt sınıftaki Criteria'u geçersiz kıldığımda, MatchDay yerine IChromosome kullanmak zorunda olduğum anlamına gelir (MatchDay'un belirli özelliklerine erişmem gerekiyor). Basit aklımda, seçenekler 1 ve 2 eşdeğerdir. Seçenek 2, IChromosome'un IChromosome'u uygulayan bir sınıfla sınırlı olan genel tür U ile değiştirir.

Mümkün olanı başarmaya çalışıyorum mı? Öyleyse, ne eksik/yanlış anlama var? Eğer değilse, bu probleme nasıl yaklaşmalıyım?

(Ben soruyla yardımcı ne kadar emin değilim olarak sonuna eklenmiştir) Bütünlüğü için

, burada şu anda T (Season) ve U (MatchDay) için kullanıyorum iki kuruluştur.

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; } 
    } 
} 
+0

Hangi sürüme sahiptir.net framework kullanıyor musunuz? –

+0

.NET sürüm 4 - tam sürüm istemci profili değil. Cevap sürüme bağlı olarak değişiyor mu? İlginçse Visual Studio 2010'u kullanın. – Stu

+0

Delegate covariance ve contravariance, sürüm 4.0 –

cevap

8

Eh bu sorunun:

public IEnumerable<IChromosome> Chromosomes 

Sen sadece Eğer IChromosome değerlerinin bir dizisini dönüyoruz beyan ediyoruz. Ölçütünüz MatchDay değerlerini bekliyor. , aslında MatchDay değerlerini döndürdüğünü biliyor, ancak derleyici bunu yapmıyor.

return season.Chromosomes.Cast<U>().Count(Criteria); 

... ya da bir IEnumerable<MatchDay> dönmek için Chromosomes değişebilir:

Sen yürütme zamanda bu kontrol etmek Cast<> kullanabilirsiniz. Ne yazık ki, bunun geçerli bir cevap olup olmadığını gerçekten söyleyemeyiz ya da ICrossoverable'un nasıl bildirildiğini bilmiyoruz. Belki eleman türünde ICrossoverable jenerik yapmalısınız?

+0

Ah ha! Bu temizler. Bence asıl çözüm senin son cümlende yatıyor - 'ICrossoverable' jenerik yap. Bunu yarın deneyeceğim ve rapor edeceğim. – Stu

+2

Önerildiği gibi, sorunumu çözen "ICrossoverable" jenerik yaptım. Kod, [Github deposum] 'da (https://github.com/hungryhippo2312/GeneticAlgorithm). Genetik algoritma terminolojisi ile çok daha iyi uyuştuğu için ICOSsoverable'ı IOrganizm'e dönüştürdüm. KriterlerBase 'un bir uygulaması [başka bir Github deposunda] bulunabilir (https://github.com/hungryhippo2312/FixtureGenerator/blob/master/FixtureGenerator/Criteria/SuperSundayCriteria.cs). Birden çok ve çeşitli öneriler için teşekkürler. – Stu

3

Sen CriteriaBase tanımında U önce anahtar kelime in kullanmalıdır. Böyle bir şey:

public abstract class CriteriaBase<T, in U> 
    where T : ICrossoverable 
    where U : IChromosome 

Güncelleme. Çalışmayacak. yazın belirtmek için deneyin açıkça

private int GetNumberOfCriteriaMatches(T season) 
{ 
.... 
    return season.Chromosomes.Count<IChromosome>(Criteria); 
} 
+0

'dan itibaren çalışıyor. Bunu yaptığımda, "Varyant tipi parametrelerin yalnızca arabirimlerde veya temsilcilerde bildirilebileceğini" belirten bir derleyici hatası alıyorum. Üç soru: 'in' ekleme ne yapar, bu hata ne anlama geliyor ve neden çalışmıyor? Teşekkürler! – Stu

+0

Bunun sadece delegeler ve arayüzler için işe yaradığını unutmayın. Tamam. Daha açık bir şekilde belirtmek için (ölçüt) –

+0

belirtmeye çalışın Şimdi farklı bir hata var! 'System.Func ' argüman türü 'System.Func ' parametresine atanamaz. Neredeyse U: IChromosome'un olmadığı yerde! Şimdi nerde? – Stu