C # generics ішіне кірістірілген сыныпта пайдалану

Келесі сынып құрылымын қарастырайық:

public class Foo
{
    public virtual void DoSomething()
    {
    }

    public class Bar where U : Foo, new()
    {
        public void Test()
        {
            var blah = new U();
            blah.DoSomething();
        }
    }
}

public class Baz
{
}

public class FooBaz : Foo
{
    public override void DoSomething()
    {
    }
}

Мен кірістірілген сыныпты пайдаланған кезде, келесідей нәрсе бар:

var x = new FooBaz.Bar();

Мүмкін, оны екі рет көрсету керексіз. Мен мұны өзімнің класс құрылымын қалай жасауға болатындай етіп жасауға болады?

var x = new FooBaz.Bar();

Кірістірілген сыныптың қай жерде екенін U әрдайым ата-ана деп айтуға қандай да бір жол керек емес пе? Қалай?


Жаңарту: Түсініктемелерді шешу үшін жоғарыда келтірілген DoSomething() әдістерін қосыңыз. DoSomething деп атаған кезде, ол алдын ала жазылған нұсқаға қатысты. Егер мен жай U-ның орнына Foo-ды қолдансам, онда оның базалық іске асуы деп аталады.

6
Foo жеткіліксіз, себебі мен FooBaz-те әдістерді анықтай алмас едім. Егер Bar тек Foo сілтемесін қолданса, ол Foo базалық іске асыруды қолданады.
қосылды автор Matt Johnson, көзі
Егер сіз «жаңа Foo ()» деп айтатын болсаңыз, біреу анықталғандықтан автоматты түрде FooBaz алмайсыз. Мен мәселені кейбір әдістермен жаңартамын, осылайша сіз көре аласыз.
қосылды автор Matt Johnson, көзі
IMO Сіз жасай алатын ең жақсы нәрсе - қазір істеп жатқан нәрсе.
қосылды автор Saeed Amiri, көзі
Bar ішінде U қалай пайдаланасыз? Foo қолданбаса, орнына жеткілікті емес пе?
қосылды автор svick, көзі
Егер сізде алдын-ала әдістер болса, онда сізде Foo данасы бар және бұл Foo FooBaz кейбір әдістерді алдын ала анықтаса, олар шақырылатын болады. Осылайша виртуалды әдістер жұмыс істейді.
қосылды автор svick, көзі

3 жауаптар

Егер class Bar жалпыға арналған қажет болмаса, неге оны біреу жасайсыз?

Бұл жұмыс істейді:

public class Foo where U : Foo
{     
    public class Bar
    {
        private T t;
        private U u;
    }
}

public class Baz
{
}

public class FooBaz : Foo
{
}

Содан соң

var bar = new FooBaz.Bar();

Әрине, мұның барлығы мүлдем дерексіз, сондықтан ол практикалық мысалға қолданылуы мүмкін немесе мүмкін емес. Мұнда сіз дәл осында жетуге тырысасыз?

3
қосылды
Жақсы, бұл мүмкін жұмыс істейді, бірақ мен FooBaz анықтамасында жазылған рекурсия туралы сенімді емеспін. Мен оны сынап көремін.
қосылды автор Matt Johnson, көзі
Әрине, бұл шынымен де жұмыс істейді. Бірақ бұл баланың орнына ата-аналық сыныпқа артық сипаттаманы ауыстыру ғана емес. Менде көп бар Foo қарағанда бар, сондықтан менің ойымша, мен оны қалдырып, бастапқыда көрсеткендей. Негізінен, бұл шешім бірдей сұрақ қояды, алайда АНТАН-дан емес, өзін өзі бағалау. Бәрібір рахмет.
қосылды автор Matt Johnson, көзі
U контейнерлік сыныпта пайдалы емес, неге оны жалпы параметр ретінде беру керек?
қосылды автор Saeed Amiri, көзі
@Jon, егер пайдалы болса, оларды контейнерлік сыныпқа қосыңыз. біз көре алатынымыз туралы ғана айтуға болады
қосылды автор Saeed Amiri, көзі
@SaeedAmiri: Бұл мүмкін болғандықтан пайдалы (Мен осыған қатысты кеңестер үшін T және U түрлерінің өрістерін қосқанмын). Бұл қалай екенін білесіз бе?
қосылды автор Jon, көзі

Жоқ, сіз оны біріктіре алмайсыз.

Foo ішіне сізде T және U, 2 әртүрлі типтер бар және компилятор U үшін түрін жасай алмайды, тек оны шектеуі керек.

2
қосылды
Бұл жерде мен StackOverflow екі қабылданған жауапты таңдауға мүмкіндік беруі мүмкін. Бұл шындық. Бірақ Джонның жауабы біршама егжей-тегжейлі. Бәрібір рахмет.
қосылды автор Matt Johnson, көзі

Why do you introduce U at all? Can you not replace its use everywhere within the definition of Bar with Foo?

0
қосылды
Тағы да, жоқ. FooBaz-та FooBaz-тегі әдістерді асыра алмайтындықтан, Foo функциясын қолдану жеткіліксіз. Егер Bar тек Foo сілтемесін қолданса, ол Foo базалық іске асыруды қолданады.
қосылды автор Matt Johnson, көзі
Жақсы, бұл маған алғашқы сұрағынан түсініксіз болды. Сондықтан мен сізді не себепті енгізгеніңіз туралы сұрадым.
қосылды автор Frank, көзі