[ Shadowed @ 07.09.2014. 21:39 ] @
Zamisao:

Code (csharp):

public interface IBar
{
    void BarDo();
}

public interface IFoo
{
    List<IBar> Bars {get;set;}
}

public class MyClass
{
    public IFoo FooImplementation {get;set;}

    public void Do()
    {
         FooImplementation.Bars.ForEach(b => b.BarDo());
    }
}
 


Code (csharp):

public class Bar : IBar
{
    public void BarDo() { }
}

public class Foo : IFoo
{
    public List<Bar> Bars {get;set;}
}

public class Program
{
    public void Main()
    {
        MyClass mc = new MyClass();
        mc.FooImplementation = new Foo();
        mc.Do();
    }
}
 



Ok, kod je neispravan ali oslikava sta hocu. Dakle, problem je sto List<Bar> Bars nije implementacija List<IBar> Bars. To je jasno i logicno (iako malo kontraintuitivno) i to nije problem.

Problem je sto mi stao mozak i nemam ideju kako da uradim na drugi nacin... :)
[ ravni @ 08.09.2014. 09:22 ] @
Mozda
Code (csharp):

public class Foo : IFoo
{
    public List<IBar> Bars {get;set;}
}
 
?
[ Shadowed @ 08.09.2014. 09:36 ] @
Moram imati konkretnu implementaciju*. OK bi bilo da imam i jedno i drugo kada bih mogao u getter-u za List<IBar> Bars da vracam istu listu koja je i za property tipa List<Bar>. Imao bih dupli property ali to nije problem, nego je problem sto ne moze :)


*Ovo je pojednostavljen primer, Bar je zapravo entity klasa za EntityFramework a Foo je interface koji klasa koja nasledjuje DbContext treba da implementira. DbContext ne prihvata interfejs, samo klasu.
[ deerbeer @ 08.09.2014. 09:52 ] @
Citat:

Moram imati konkretnu implementaciju*.

Ondak ti verovatno ne treba interfejs :)
[ Shadowed @ 08.09.2014. 10:00 ] @
Treba mi :) OK, ne obavezno, ali ne vidim kako drugacije.

Ako pogledas prvi kod, tamo je klasa MyClass koja nesto radi sa tim interfejsima a potrebno je da joj se ubaci konkretna implementacija.
[ deerbeer @ 08.09.2014. 10:13 ] @
onda mozda ovako nesto
Code:

public class Foo<T> : IFoo
{
    public List<T> Bars {get;set;}
}

al je onda IFoo suvisan kao sto sam rekao tj. mislim (nisam siguran) da ne mozes da templejtizujes interfejs


[ mmix @ 08.09.2014. 10:16 ] @
Ok, sad cu da pogledam da probam da prokapiram sta ste hteli, ali interfejsi definitivno mogu da budu generic. Npr IList<T>, implementirajuca klasa mora da ili specijalizuje tip (class A: I<int>) ili da prenese generalziaciju (class A<T>:I<T>)

[ mmix @ 08.09.2014. 10:35 ] @
Ovako radi:

Code (csharp):

using System;
using System.Collections.Generic;
using System.Linq;

namespace SampleClasses
{

    public interface IBar
    {
        void BarDo();
    }

    public interface IFoo<T> where T:IBar
    {
        List<T> Bars { get; set; }
    }

    public class MyClass<T> where T:IBar
    {
        public IFoo<T> FooImplementation { get; set; }

        public void Do()
        {
            FooImplementation.Bars.ForEach(b => b.BarDo());
        }
    }

    public class Bar : IBar
    {
        public void BarDo() { }
    }

    public class Foo<T> : IFoo<T> where T: IBar
    {
        public List<T> Bars { get; set; }
    }

    public class Program2
    {
        public void Main()
        {
            var mc = new MyClass<Bar>();
            mc.FooImplementation = new Foo<Bar>();
            mc.Do();
        }
    }
}
 
 

[ Shadowed @ 08.09.2014. 10:47 ] @
Hvala. Probao sam nesto slicno ali mi nije proslo a vec bilo kasno sinoc :)

Samo sto mislim da necu moci da imam <T> u MyClass<T>. Provericu. A takodje i da li moze bez a da
public IFoo<T> FooImplementation { get; set; }
bude
public IFoo<IBar> FooImplementation { get; set; }

Edit: Hm, sad kapriam da IFoo<IBar> FooImplementation nece moci, imacu slican problem kao na pocetku teme.
[ mmix @ 08.09.2014. 11:05 ] @
Ako ti je to finalna klasa ui ne radis dalju generalizaciju ti mozes da radis specijalizaaciju u MyClass. Mada ceo ovaj primer zece krsi enkapsulaciju, MyClass bi trebao da pravi svoj FooImplementation

Code (csharp):

public class MyClass
     {
         public IFoo<Bar> FooImplementation { get; set; }

         public void Do()
         {
             FooImplementation.Bars.ForEach(b => b.BarDo());
         }
     }

     ...

     public class Program2
     {
         public void Main()
         {
             var mc = new MyClass();
             mc.FooImplementation = new Foo<Bar>();
             mc.Do();
         }
     }
 
[ Shadowed @ 08.09.2014. 11:29 ] @
public IFoo<Bar> FooImplementation { get; set; }
ne moze da se uradi, jer MyClass ne zna za Bar implementaciju. Implementacija je u zasebnom asembliju.
[ mmix @ 08.09.2014. 11:31 ] @
Onda moras da ga setas
[ tdusko @ 08.09.2014. 11:34 ] @
Pocetna verzija koda koji je Shadowed postavio je klasican primer ogranicenja generics-a u C# jer su invariant. Odnosno ne podrzavaju covariance/contravariance. Na primer, ako bi se IFoo u pocetnoj verziji zamenio sa

Code:
public interface IFoo
{
     IBar[] Bars {get;set;}
}


compiler ne bi prijavio gresku, ali bi se raspao u toku izvrsavanja. Zaobilazenje ovog limita genericsa obicno dovodi do narusavanja nekog od OO principa.

C# in Depth knjiga poglavlje 3.5.1 lepo to objasnjava
[ mmix @ 08.09.2014. 17:04 ] @
Ima tu resenja sa promenom varijance interfejsa. Npr:

Code (csharp):

    public interface IBar
    {
        void BarDo();
    }
    public interface IBar2: IBar
    {
    }

    public interface IFoo<out T> where T: IBar
    {
        IEnumerable<T> Bars { get; }
    }


    public class Bar : IBar
    {
        public void BarDo() { }
    }

    public class Bar2 : IBar2
    {
        public void BarDo() { }
    }



    public class Foo<T> : IFoo<T> where T: IBar
    {
        public List<T> Bars { get; set; }

        IEnumerable<T> IFoo<T>.Bars
        {
            get { return Bars; }
        }
    }


    public class MyClass
    {
        public IFoo<IBar> FooImplementation { get; set; }

        public void Do()
        {
            foreach (var e in FooImplementation.Bars) e.BarDo();
        }
    }

    public class Program
    {
        public void Main()
        {
            MyClass mc = new MyClass();
            // mc.FooImplementation = new Foo<Bar>();   // moze ovo
            mc.FooImplementation = new Foo<Bar2>();   // a moze i ovo (covariance)
            mc.Do();
        }
    }
 
[ 30yo @ 08.09.2014. 18:22 ] @
Citat:
Shadowed:Dakle, problem je sto List<Bar> Bars nije implementacija List<IBar> Bars.

nije to problem jer nije ovo prosledjivanje argumenta metodi. kada implementiras metodu/svojstvo interfejsa ili apstraktne klase ili radis override virtuelne metode, moras da "prepises" doslovce potpis metode i povratnu vrednost i modifikatore jer su to jedni jedini podaci o tom clanu, ne mozes da ih menjas kako hoces.
[ Shadowed @ 08.09.2014. 20:43 ] @
Pa da, mora, a to se ne uklapa Da je IEnumerable<Bar> moglo bi (jer je IEnumerable<out T>. Medjutim, meni treba ICollection ili bilo sta sto ga nasledjuje ili implementira a on ne moze, jer nema "out".


Elem, hvala svima, mmix-ovo resenje mi odgovara. Morao sam da proverim da li ce neke druge stvari nevezane za ovaj problem moci da rade ako je MyClass generic (tj. ima type parameter). Provereno je, moze, dakle to je to
[ 30yo @ 08.09.2014. 22:19 ] @
nije ovo stvar polimorfizama i varijacije, nego cisto prekucavanje metapodataka. Bars je jedno svojstvo koje ima deklaraciju na dva mesta, i ne moze na jednom da pise da mu je tip IEnumerable<IBar> a na drugom IEnumerable<Bar>.
[ mmix @ 09.09.2014. 00:33 ] @
Nije mi bas najjasnije sta si hteo da kazes.
[ 30yo @ 09.09.2014. 02:57 ] @
hteo sam da kazem da je po meni ovo

public interface IFoo
{
IEnumerable<IBar> Bars {get;set;}
}
public class Foo : IFoo
{
public IEnumerable<Bar> Bars {get;set;}
}

isto kao da si pokusao da napises

public IEnumerable<IBar> IEnumerbale<Bar> Bars {get;set;}
[ mmix @ 09.09.2014. 09:49 ] @
Pa nije isto. Na stranu sintaksna greska, radi se o jednostavnoj implementacij contracta (interfacea). Instancu klase uvek mozes da castujes u interfejs koji implementira I da pristupis preko elemenata interfejsa.

IEnumerable<Bars> treba da moze da se vidi kao IEnumerable<IBar> i u tu svrhu su i uvedene varijacije u C#. Sam objekat koji implementira IEnumerable<out T> ne mora da kovarijantan, vazno je samo da ima kovarijantnu implementaciju IEnumerable<out T> interfejsa. List<T> u Foo<T> koji sam dao ima kovarijabilni IEnumerable<IBar> jer je sa where uslovom u Foo<T> ograniceno da samo implementacije IBar-a mogu da prodju. Ostalo handluje kovarijabilnost.