HDSoftware Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Folkens, hvorfor funker ikke følgende: List<lstRecord> records = new List<lstRecord>; var kunder = from r in db.Kunder select r; foreach(var rec in kunder) records.Add(rec); class lstRecord : Kunder { // Properties som beregner kunderelatert data } Vet jeg kan gjøre mye av det samme direkte i LINQ uttrykket, men alikevel, hvorfor virker det ikke? Lenke til kommentar
GeirGrusom Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 (endret) Du kan ikke implisitt up-caste. lstRecord => Kunder, men Kunder =\> lstRecord. Du kan bruke operator as for å caste til lstRecord. Sjekk omr esultatet ble null for å sjekke om castingen funket eller ikke. Endret 10. mai 2011 av GeirGrusom Lenke til kommentar
MailMan13 Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Du kan bruke Linq sin OfType<T>() for å gjøre "safe cast", eller Cast<T>() av alle. var kunder = from r in db.Kunder select r; var records = kunder.OfType<lstRecord>().ToList(); Lenke til kommentar
GeirGrusom Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Kanskje dette er litt simplere: var kunder = from r in db.Kunder select r as lstRecord; Forskjellen på den og MailMan13 er dog at min kan returnere null objekter dersom noen ikke lar seg konvertere. Kommer helt an på koden din dog. Lenke til kommentar
HDSoftware Skrevet 10. mai 2011 Forfatter Del Skrevet 10. mai 2011 Pussig. Jeg prøvde nemlig AS slik : lstRecord r = kunde as lstRecord og det funket ikke. Men kansje det funker i LINQ uttrykket. Jeg har uansett skrevet om lstRecord klassen slik at den ikek arver, men tar Kunde som komponent i stedet. Dermed lagede jeg bare nye properties for hvert felt. Funker greit, men jeg synes det er litt sølete dog. OfType<t> har jeg ikke prøvd. Må sjekke ut den og se hva den kan tilby... Lenke til kommentar
GeirGrusom Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Pass på at objektet faktisk lar seg caste. Det er vanskelig å se utifra koden din. Eksempelvis: class A { } class B : A { } class Program { static void Main() { var a = new A(); var b = new B(); var c_b = (A)b; // Lovlig var c_a = (B)a; // Ulovlig! Dette vil gi exception } } Lenke til kommentar
HDSoftware Skrevet 10. mai 2011 Forfatter Del Skrevet 10. mai 2011 og det er nok der jeg feiler. Klassen lstRecord er jo et derivat av Kunder slik at lstRecord inneholder mer. Men jeg trodde man kune sjongelere begge veier her så lenge de deler et minimum. Og i mitt tilfelle er jo lstRecord en utvidet versjon av Kunder. En skulel jo dermed tro at man kunne ha en lstKunder som en referanse av Kunder. Rart igrunn at det ikke går. Skjønner det ikke helt. Hadde det vært andre veien - altså at man ikek kunne hatt en Kunde record basert på lstRecord så hadde jeg forstått det. Men men, ikke alt man skall forstå her i verden ;-) Anyway - ting virker nå etter at jeg skrev om litt.. Takker for inspill.. Lenke til kommentar
GeirGrusom Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 (endret) Grunnen er at oppførselen til objektet ville blitt udefinert dersom du caster oppover. Sett av vi ser for oss minneområdet til den imaginære klassen Uke: class Uke { public int Uke { get; set; }; }[code] class UkeDag : Uke { public int Dag { get; set; }; } UkeDag Add(UkeDag a, UkeDag b) { return new UkeDag() { Uke = a.Uke + b.Uke + (a.Dag + b.Dag) / 7, Dag = (a.Dag + b.Dag) % 7 } } Hva skal skje i Add dersom a eller b egentlig er Uke, ikke UkeDag? Innholdet i Dag vil være udefinert, og programmet vil være helt uforutsigbart. Programmet måtte ha konstruert et helt nytt objekt som fylte inn manglende informasjon, og en kan ikke forvente at .NET skal fikse dette for deg. Skal upcaste, kan du override casting for det objektet, eller lage en funksjon som genererer et korrekt objekt. For å override cast kan du gjøre slik: public static explicit operator UkeDag(Uke input) { return new UkeDag() { Uke = input.Uke, Dag = 0 }; } Endret 10. mai 2011 av GeirGrusom Lenke til kommentar
torbjørn marø Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 (endret) HDSoftware, du har nok missforstått. Forsøker meg på en basic forklaring: La oss si at du har klassen Animal, og at denne har metoden MakeSound(). Og så har du klassan TwoLeggedAnimal, som arver fra Animal og i tillegg har metoden Walk(). Om du så oppretter en List<TwoLeggedAnimal> så garanterer du at alle objekter du legger inn der både kan lage en lyd og kan gå. Du kan derfor ikke legge inn andre typer dyr. Oppretter du en List<Animal> kan den også inneholde TwoLeggedAnimal, fordi det eneste du har garantert er at alle objektene kan lage en lyd. Gir det mening? Endret 10. mai 2011 av torbjørn marø Lenke til kommentar
MailMan13 Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 og det er nok der jeg feiler. Klassen lstRecord er jo et derivat av Kunder slik at lstRecord inneholder mer. Men jeg trodde man kune sjongelere begge veier her så lenge de deler et minimum. Andre har forklart hvorfor, men tenk deg: class A { } class B : A { } class C : A { } var list = new List<B>(); // Ok, B er A, så dette må være greit!?! List<A> generiskList = list; // går fint, C er jo en A og må kunne legges til i en liste av A generiskList.add(new C()); // oops, list var liste av B, men nå har vi fått en C inn her... var first = list[0]; Denne typen covariance du ønsker får man i C# 4.0 om "out"-keywordet er brukt på den generiske typen. Et krav da blir at man bare kan dra objekter av den generiske typen ut, og ikke dytte den inn, så man vil ikke kunne lage en muterbar liste som benytter den funskjonaliteten IEnumerable er f.eks deklarert slik, så du kan f.eks si IEnumerable<object> list = new string[] {"hei og hopp"}; Siden vi ikke kan mutere IEnumerable kan ikke situasjonen over oppstå, og Microsoft kunnet deklarere typeargumentet "out" på IEnumerble. Lenke til kommentar
HDSoftware Skrevet 10. mai 2011 Forfatter Del Skrevet 10. mai 2011 Ja, det gir mening, men er det ikke akkurat det jeg sier da? Altså, jeg har klassen Kunde, som inneholder alt om en kunde. SÅ har jeg en klasse FullKunde som også inneholder funksjonalitet som forteller om kundes ordre og slikt Skal ikke jeg da kunne lage et FullKunde objekt på bakgrunn av Kunde ? Eller er det kunn mulighet til å hente ut "kunde" delen av en FullKunde ? hmm - når jeg tenker etter så høres jo det fornuftig ut. Men dog... Gitt følgende eksempel: class Kunde { string Navn string Adresse string Postnr } class KundeMedAdresse : Kunde { string Poststed { get{ return GetPoststed(this.Postnr); } } } Dette må jo gå an.. Så kommer bruken av dette inn i koden min var kunder = from k in db.Kunder select k; // Nå vil kunder inneholde ALLE kundene foreach(var k in kunder) lstKunder.Add(k); Her vil det feile fordi man altså sier at objektet ikke vet nok om seg selv. Jeg ser ikke hvorfor i dette tilfellet. @GeirG: Jeg ser jo problemstillingen med upcasting som parametere på den måten og ser hvorfor dette vil feile, men blir det det samme som mitt eksempel da? Kan det være at jeg burde tenkt Extension class eller noe slikt? Er det ikek noe som heter det i C# da? Vil det løse dette? Eller er det bare en annerledes måte å se på nedarving og derav feile på samme måte? Lenke til kommentar
MailMan13 Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Bommet kanskje litt på problemstillingen med covariance-begrepet. ikke helt det som er problemet her. (Så hvilke vei arven var...) men blir det det samme som mitt eksempel da? Ja, det blir et problem. Du har en liste av lstRecord, så prøver du å tilordne en Kunde, men Kunde arver ikke fra lstRecord, så den tilordningen er ikke lov. En referanse av type Kunde kan peke på en lstRecord, fordi lstRecord arver fra og er en Kunde. Så en List<Kunde> kan innehodel lstRecord-objekter. Men det du prøver på er motsatt. En referanse av type lstRecord kan peke ikke peke på en Kunde, fordi Kunde ikke arver fra og ikke er en lstRecord. Så en List<lstRecord> kan ikke inneholde Kunde-objekter. Lenke til kommentar
GeirGrusom Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Jepp. Du må i så fall bygge lstRecord utifra Kunde. Enten med constructor, funksjon eller casting operatør. Lenke til kommentar
HDSoftware Skrevet 10. mai 2011 Forfatter Del Skrevet 10. mai 2011 (endret) Ja, jeg ser den... DU har rett. Hehe, ble liksom så ivrig når jeg skulle lage den klassen fordi det så så elegant ut bare å lage en utvidet klasse i stedet for å implementere hele grunnklassen. Fungerer selvsagt nå men ndet er fordi jeg har en konstruktør som tar imot Kunde og dermed fungerer det. Dog uten arving fra Kunde så klart. Kunn som komponent. class Kunde { string navn; string Adresse; string Postnr; } class FullKunde { Kunde rec; string Adresse { get{ return rec.Adresse; } set{ rec.Adrese = value; } } etc. string Poststed { get{ return GetPoststed(rec.Postnr); } } public FullKunde(Kunde pRec) { rec = pRec; } } Som sagt, komponent basert, men MYE mere skriving. Kansje dere har en ide om hvordan man kan få dette til mere elegant alikevel ? ;-) Bare for morro skyld altså.. Endret 10. mai 2011 av HDSoftware Lenke til kommentar
MailMan13 Skrevet 10. mai 2011 Del Skrevet 10. mai 2011 Hvis det er Entity Framework mener jeg alle klassene er "partial" ja. Så du skal kunne bygge videre på den i en annen kildekodefil i samme assembly. Inni designer.cs til datasourcen har du en autgenerert klasse som er partial: [EtEllerAnnetEntityFrameworkAttribute] public partial class Kunde : EntityObject { [EtAnnetEntityFrameworkAttribute] public string Name {...} } Da skal du kunne legge til en ny kildefil i samme prosjekt og forsette på den: public partial class Kunde { public void SayHello() { Console.WriteLine("Hello, " + this.Name()); } } Lenke til kommentar
HDSoftware Skrevet 11. mai 2011 Forfatter Del Skrevet 11. mai 2011 Hmm. Du har rett. Partial ville løst problemet mitt. Hmmm. Rart jeg ikek tenkte på det?!?! Har jo brukt PARTIAL på en hel drøss andre klasser.. Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå