[ Boris B. @ 08.12.2010. 15:50 ] @
Imam objekt deklarisan prosto kao npr. object Datasource. U designtime-u nemam pojma sta ce taj datasource biti, moze da bude obican object, moze da bude IEnumerable<T> a moze da bude i EntityCollection<T>.

Potrebno mi je:
Code (csharp):

if (Datasource is EntityCollection<T>)
   ((EntityCollection<T>)Datasource).Load(...)
 


Problem je u tome sto ako ga napisem tako onda moram da deklarisem <T> u potpisu metoda ili u klasi, a onda moram da propagiram <T> svuda gde se pomenuti metod (ili klasa) koristi, sto nema smisla jer ne znam unapred <T> koga mozda i nema u slucaju da Datasource is object.

Ako ga probam "kovariantno" kao
Code (csharp):

if (Datasource is EntityCollection<object>)
   ((EntityCollection<object>)Datasource).Load(...)
 
.
...onda nikada ne prodje if proveru, jer nijedan EntityCollection<T> is EntityCollection<object>, osim kad typeof(T) == typeof(object), sto je u praksi nikada.
[ mmix @ 08.12.2010. 16:06 ] @
Hmm, pa sve i da mozes da proveris kako bi ga bas castovao u Generic<T>?

dynamic + refleksija?

[ Boris B. @ 09.12.2010. 08:33 ] @
Pa proveru pretpostavljam da bi mogao preko classname-a, if StartsWith("EntiyCollection") then profit!.

Dynamic sa druge strane ima jednu jaaaako nezgodnu i nedokumentovanu osobinu. Naime kad imas neki objekat kao dynamic svi dinamicki pozivi metoda ili property-ja rade doklegod su ti metodi i property-ji deklarisani u istom asembliju kao i sama klasa. Ako imas neki override u descendantu koji je u drugom asembliju onda virtualni pozivi nastali u prvom nece videti override iz drugog. Tradicionalan nacin (GetProperty/MethodInfo) nema to ogranicenje. Ovo sam nazalost otkrio na tezi nacin.
[ mmix @ 09.12.2010. 08:45 ] @
Cek bre, override-ovi bi morali da rade, ono sto ne radi sigurno su extensions (koji su u stvari u CLRu staticki pozivi koje kompajler "prevarom" dozvoljava kao instance pozive). Medjutim etension metod bi trebao da mozes da pozoves direktno.


A sto se tice EntiyCollection, Type bi morao da ima njegovo ime bez generic parametara, generici se definisu kao atributi Type tipa.
[ Boris B. @ 09.12.2010. 09:19 ] @
Ma ne rade veruj mi. Evo ti konkretan primer:

Osnovni assembly:
- Imam svoju baznu klasu EntityWrapper<T> i virtualni metod Validate().
- Klasa DataManager ima metod ValidateEntity(EntityObject entity).
- Taj ValidateEntity mora da pozove EntityWrapper<typeof(entity)>.Validate(). Najpre mora da nadje wrapper, instancira ga i pozove Validate. Zbog onog <T> ne mogu da staticki zovem Validate jer ne znam T unapred.

Aplikativni assembly:
- Imam klasu Osoba: EntityObject i wrapper OsobaWrapper: EntityWrapper<Osoba>
- Klasa OsobaWrapper override-uje metod Validate i radi validaciju entiteta.


E sad, kad u osnovnom asembliju u DataManager.ValidateEntity napisem:
Code (csharp):

  dynamic wrapper;
  // Nadjem odgovarajuci wrapper preko mog atributa i instanciram ga sa Activatorom. Onda zovem:
  wrapper.Validate(entity);
 


E ovde taj Validate ne radi, iako wrapper referencira pravu instancu !
Ako napisem ovako onda radi:
Code (csharp):

   // Nadjem wrapper preko atributa
   Type wt = (
               from wrapperType in
               (
                   from assembly in AppDomain.CurrentDomain.GetAssemblies()
                   from type in assembly.GetTypes()
                   where type.IsDefined(typeof (EntityWrapperAttribute), false)
                   select type
               )
               from attribute in wrapperType.GetCustomAttributes(false)
               where ((EntityWrapperAttribute) attribute).EntityType.Equals(entity.GetType())
               select wrapperType
            ).FirstOrDefault();

   // Instanciram ga
   var instance = Activator.CreateInstance(wt, Entities, this);

   // Dinamicki zovem Validate
   return wt.GetMethod("Validate").Invoke(instance, new object[] { entity });
 



Ocigledno dynamic ne radi za override u drugom asembliju.
[ mmix @ 09.12.2010. 10:10 ] @
Ajd probacu za pola sata, ali ne bi smelo da ne radi, sa stanovista objekata ne postoji cross-assembly bariera, sve je to deo istog domena. Da ne radi cross-assembly ne bi ti radila skoro nijedna klasa iz frameworka jer vecina instanci end klasa imaju "mesovite" virtuelne tabele.

[ mmix @ 09.12.2010. 13:26 ] @
OPk, problem nije do asemblija, problem je u runtime resolvingu, tj isti onaj problem koji si probao da zaobidjes u compile time-u

Kad kreiras instancu wrappera njegov potpis Validate metoda je

EntityWrapper<Osoba>.Validate(Osoba)
Greska je jasna: The best overloaded method match for 'MyCoreAssembly.EntityWrapper<SampleDynamicGen.Osoba>.Validate(SampleDynamicGen.Osoba)' has some invalid arguments

dynamic ne radi overload rezoluciju po runtime tipu parametra ako parametar sam nije dynamic, a tebi nije, definisan je kao EntityObject. E sad dal su mogli da odu jos taj jedan korak napred, to je vec za diskusiju jer je to dalji pad performansi i dodatna dimenzija pretrazivanja overloada, u principu retki su problemi kao tvoj da ne znas T pa ne mozes da castujes objekat. Resenje za dynamic je dynamic-full-on , castuj parametar u dynamic i nateraj resolver da uradi i taj matching (isto sam ti u primeru dao i kako da lociras wrapper bez atributa)

Code (csharp):

            // bez atributa
            // Nadjem wrapper preko atributa
            Type wt = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
                       from type in assembly.GetTypes().Where(t => t.BaseType!= null && t.BaseType.IsGenericType)
                       where (type.BaseType.GetGenericTypeDefinition() == typeof(EntityWrapper<>)) && (type.BaseType.GetGenericArguments()[0] == entity.GetType())
                       select type).FirstOrDefault();

            // Instanciram ga
            dynamic instance = Activator.CreateInstance(wt);
            instance.Validate((dynamic)entity);
 




A ono drugo sto sam hteo da te pitam, sto ne ubacis factory patern za wrapper u EntityObject? Imas u solutionu, ali onda se na kraju datamanageru svodi na

Code (csharp):

        public void ValidateEntityOldSchool(EntityObject entity)
        {
            entity.GetWrapper().Validate(entity);
        }
 


mislim da ti generici ne trebaju uopste ovde.
[ Boris B. @ 09.12.2010. 14:12 ] @
Hvala puno za odgovor, mada mi i dalje nije jasno sta se tu desilo:

>EntityWrapper<Osoba>.Validate(Osoba)
>Greska je jasna: The best overloaded method match for 'MyCoreAssembly.EntityWrapper<SampleDynamicGen.Osoba>.Validate(SampleDynamicGen.Osoba)' has some invalid arguments
I dalje mi nije mi jasno gde je greska.
Bazni metod je EntityWrapper<T>.Validate(T entity). Samim tim izvedeni je EntityWrapper<Osoba>.Validate(Osoba entity). Zahvaljujuci templatingu to je isto kao da pise EntityWrapperOsoba.Validate(Osoba entity). Ako imam instancu EntityWrapperOsoba u dinamickoj referenci dynamic r i pozovem r.Validate(Osoba o), ako o jeste osoba (a jeste) onda nema razloga za pomenutu gresku. Procitacu par puta tvoj post pa ce mi valjda biti jasno

EDIT:
Aha sad mi je jasno, on trazi OsobaWrapper.Validate(EntityObject osoba) i ne naravno ne moze da ga nadje. Hvala jos jednom

Sto se tice dobijanja wrapera bez atributa priznajem da nisam znao da se informacije o generickim tipovima propagiraju u runtime i da se mogu dobiti reflectionom, mislio sam da je to samo templating engine koji radi search&replace pred kompajliranjem.

Sto se predloga za factory pattern tice ne mogu da ga implementiram jer EntityObject nije moja klasa kao u tvom primeru, nego je System.Data.Objects.DataClasses.EntityObject i kada importujem bazu u model svi entiteti (npr. Osoba) nasledjuju taj EntityObject. EF4 podrzava POCO, ali je to dosta vise posla i zaboravi na GUI model editor. Upravo zbog toga sam i pravio te wrappere, inace bi Validate bio metod klase EntityObject. Wrapperi pored Validate imaju i New, Query i Delete, a te operacije su vezane na ObjectContext i zato su u DataManageru, jer mi Datamanager enkapsulira i kontekst i UnitOfWork. Na ovaj nacin je kontekst i sve ostalo data-aware odvojeno u svom assembliju, i ostatak programa (GUI, WebPage...) radi samo sa objektima.

[Ovu poruku je menjao Boris B. dana 09.12.2010. u 15:35 GMT+1]

[Ovu poruku je menjao Boris B. dana 09.12.2010. u 15:38 GMT+1]
[ mmix @ 09.12.2010. 14:52 ] @

>mislio sam da je to samo templating engine koji radi search&replace pred kompajliranjem.

C# Generics nije isto sto i C++ templates, C# kompajler pravi specijalizaciju ali zadrzava informacije u Type objektu.