Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] Eigen methodes toevoegen aan bestaande class

Pagina: 1
Acties:
  • 177 views sinds 30-01-2008
  • Reageer

  • T_E_O
  • Registratie: Oktober 1999
  • Laatst online: 26-11 10:19
Na wat speurwerk heb ik de hoop om zelf op een antwoord te komen opgegeven. Ik ben in C# aan de slag gegaan met de api van google calendar en daar zit een class bij (EventEntry) die een event op de calendar representeert.

Ik kan uit een calendar een collection opvragen met een aantal van die events erin. Daar kan ik er eentje uithalen en die kan ik vervolgens gaan bewerken. Een van die bewerkingen is dat ik ergens in een collection met extra data zelf het veld "status" toevoeg en uitlees.

Het toevoegen en uitlezen van dat eigen veld kost elke keer een aantal regels code, doordat ik door die collection met extra data heen moet for()'en. Dat dacht ik op te lossen door een eigen class MyEventEntry toe te voegen die erft van EventEntry. In die eigen class voeg ik dan een property "status" toe met een get en een set. Die get en die set lopen vervolgens door de collection heen en voegen indien noodzakelijk het veld toe.

Dit leek me heel eenvoudig te realiseren, maar het probleem is dat C# (vast en zeker terecht) weigert om het EventEntry-object als een MyEventEntry-object te beschouwen.

Ik kwam al ergens een idee tegen van iemand om de MyEventEntry-constructor als argument een EventEntry-object mee te geven, zodat mijn constructor alle gegevens uit het EventEntry-object kan kopiëren. Dat lijkt me niet erg leuk en klinkt als een lelijke beginnersoplossing :)

Op welke wijze kan ik dit nu toch oplossen ? Ik neig er momenteel naar om gewoon lelijke setEventStatus() en getEventStatus() functies te schrijven, maar dat moet toch charmanter kunnen.

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 19:29

Haan

dotnetter

Weet je zeker dat je die MyEventEntry wel goed hebt geschreven? Post anders ook even wat (relevante) code :) Zoals je het beschrijft zou jouw manier gewoon moeten kunnen.
Aan de andere kant begint er ergens in mijn achterhoofd iets rinkelen over een manier om dit aan te pakken dmv een Interface en een wrapper class, maar ik weet niet zeker of dat om hetzelfde probleem gaat.

Kater? Eerst water, de rest komt later


  • T_E_O
  • Registratie: Oktober 1999
  • Laatst online: 26-11 10:19
Iets richting een interface en een wrapper class klinkt goed; ik hoop dat 't belletje nog wat harder gaat rinkelen :)

Mijn MyEventEntry class ziet er als volgt uit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    class MyEventEntry : EventEntry
    {
        public bool MyStatus
        {
            get
            {
                for (int i = 0; i < this.ExtensionElements.Count; i++)
                {
                    if (this.ExtensionElements[i].GetType() == typeof(ExtendedProperty))
                    {
                        if (((ExtendedProperty)this.ExtensionElements[i]).Name == "xxxx#status")
                        {
                            return (((ExtendedProperty)this.ExtensionElements[i]).Value.ToString() == "1" ? true : false);
                        }
                    }
                }
                return (false);
            }

            set
            {
                for (int i = 0; i < this.ExtensionElements.Count; i++)
                {
                    if (this.ExtensionElements[i].GetType() == typeof(ExtendedProperty))
                    {
                        if (((ExtendedProperty)this.ExtensionElements[i]).Name == "xxxx#status")
                        {
                            ((ExtendedProperty)this.ExtensionElements[i]).Value = value ? "1" : "0";
                            this.Update();
                            return;
                        }
                    }
                }

                ExtendedProperty ep = new ExtendedProperty();
                ep.Name = "xxxx#status";
                ep.Value = value ? "1" : "0";
                this.ExtensionElements.Add(ep);
                this.Update();
                return;
            }
        }
    }


Die naam van MyStatus is maar even tijdelijk en ipv die xxxx staat normaal ook wat anders, maar dit geeft een idee. Ik probeer de entry op deze manier uit de collection te plukken:

code:
1
MyEventEntry ee = (MyEventEntry) (this.feedKlusjes.Entries[i]);


Maar dat faalt met een jammerlijke exception: "Unable to cast object of type 'Google.GData.Calendar.EventEntry' to type 'HomeInterface.MyEventEntry'.".

  • whoami
  • Registratie: December 2000
  • Laatst online: 21:14
Als MyEventEntry daadwerkelijk overerft vn EventEntry, dan moet C# dit toch gewoon als een EventEntry aanschouwen ?
Echter, niet alle EventEntries zal je naar je 'MyEventEntry' kunnen casten. Veel hangt er eigenlijk ook vanaf of jij die Entries array zelf opvult of niet...
Probeer eerst eens even te checken of het object dat je terugkrijgt wel van het type MyEventEntry is. (Je kan hiervoor de as operator gebruiken, en dan checken op null).

Encapsulation (een eigen class die een EventEntry als member heeft), is niet altijd lelijk, en is ook geen 'beginnersoplossing'. In sommige gevallen kan je niet anders. (En dat is dan eigenlijk ook meteen een wrapper class).

https://fgheysels.github.io/


  • T_E_O
  • Registratie: Oktober 1999
  • Laatst online: 26-11 10:19
Die entries array vul ik helaas niet zelf. Hij wordt door de google-code gevuld met EventEntry-objecten. Ik lees her en der dat dat dan niet te casten is naar een derived class. Dat is ook wel logisch, want het type van die objecten verandert daarmee niet; alleen het uiterlijk verandert. De extra members/properties die in MyEventEntry worden toegevoegd kunnen niet zomaar een de EventEntry-objecten worden toegevoegd als ik het allemaal goed begrijp.

Hoe zou ik op de netste wijze een wrapper class kunnen maken ? Ik sla nu zoals je beschrijft het EventEntry object als member op in m'n MyEventEntry-objecten. De getter en setter van MyStatus doen hun werk nu op die member in plaats van op this.

Het nadeel hiervan vind ik dat er elke keer een instantie van de wrapper class gemaakt moet worden en dat de oorspronkelijke EventEntry-members en -methods niet rechtstreeks op MyEventEntry uit te voeren zijn, maar alleen via de EventEntry-member.

  • whoami
  • Registratie: December 2000
  • Laatst online: 21:14
T_E_O schreef op vrijdag 07 september 2007 @ 01:06:
Die entries array vul ik helaas niet zelf. Hij wordt door de google-code gevuld met EventEntry-objecten.
Logisch dan, want die google code zal die collectie niet vullen met MyEventEntry objecten dan. Dan kan je dat dus niet zomaar gaan casten, want het is geen MyeventEntry.

Ik denk dat, het makkelijkste wat je kan doen een soort 'manager' class maken, die oa methods heeft om de status van een EventType uit te lezen / te setten.
Dit doet 'the job' op dit moment, en ik zie -ook op dit moment- niet de toegevoegde waarde om er een wrapper class rond te schrijven.

[ Voor 27% gewijzigd door whoami op 07-09-2007 01:10 ]

https://fgheysels.github.io/


  • T_E_O
  • Registratie: Oktober 1999
  • Laatst online: 26-11 10:19
whoami schreef op vrijdag 07 september 2007 @ 01:09:
[...]
Logisch dan, want die google code zal die collectie niet vullen met MyEventEntry objecten dan. Dan kan je dat dus niet zomaar gaan casten, want het is geen MyeventEntry.
Dat begon ik langzamerhand al te accepteren, maar mooi dat het even bevestigd kan worden. 't Hele classes/inheritance/casting verhaal is alweer een stuk scherper.

Een wrapper class (dmv encapsulation) lijkt dus de beste manier om dit aan te pakken. Of is er nog een manier om ervoor te zorgen dat alle bestaande methods en members van de EventEntry-class ook rechtstreeks aan te roepen zijn op de MyEventEntry-objecten ?

EventEntry heeft bijvoorbeeld een member "Title". Zoals een en ander nu werkt zou de Title van een MyEventEntry-object op deze manier moeten worden aangepast:
code:
1
2
MyEventEntry mee = new MyEventEntry (een-of-ander-EventEntry-instance);
mee.ee.Title = "een mooie titel";


Edit: een manager-class is volgens mij wat ik nu gemaakt heb en bij een wrapper-class zou ik ook alle members en methodes van EventEntry beschikbaar maken in MyEventEntry, correct ?

[ Voor 8% gewijzigd door T_E_O op 07-09-2007 01:18 ]


  • Haan
  • Registratie: Februari 2004
  • Laatst online: 19:29

Haan

dotnetter

Is daar niet gewoon een SetTitle() oid voor beschikbaar?

Kater? Eerst water, de rest komt later


  • T_E_O
  • Registratie: Oktober 1999
  • Laatst online: 26-11 10:19
Nee, die is er niet, maar daar zit ik niet zo mee. Het is gewoon een read/write property van EventEntry, die misschien intern met een getter en setter werkt. Ik kan natuurlijk zelf een GetTitle() en een SetTitle() gaan toevoegen aan MyEventEntry of een property Title met een getter en setter. Het liefst zou ik echter properties en methods van EventEntry ook direct beschikbaar stellen vanaf MyEventEntry, zonder ze stuk voor stuk na te moeten lopen en na te maken.

Kortom: ik zou het liefst mee.Title = "een mooie titel"; willen kunnen schrijven zonder dat ik zelf een Title property toe moet gaan voegen.

  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 13-12-2024
je zou natuurlijk je "properties" in een collectie (dictionary) op kunnen slaan en een method maken die een propertyname als parameter krijgt en dan de value laten returnen. (even snel kort door de bocht)

Dat is snel generiek te maken.

[ Voor 7% gewijzigd door 4of9 op 07-09-2007 08:46 ]

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
als je het als mee.Title wilt kunnen accessen zul je delegating properties moeten maken. Resharper kan deze bijvoorbeeld gewoon automatisch genereren. Anders zul je zelf wat moeten typen

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyWrapper
{
    private InnerClass innerClass;

    public MyWrapper( InnerClass innerClass )
    {
        this.innerClass = innerClass;
    }

    public string Title
    {
        get { return innerClass.Title; }
        set { innerClass.Title = value; }
    }
}

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • __fred__
  • Registratie: November 2001
  • Laatst online: 29-11 20:34
Je zou ook een andere oplossing kunnen proberen:

Het overerven van de EventEntry klasse is misschien nog geen slecht idee als je ergens een aantal handvatten kunt vinden om het maken van instanties van de klasse te beinvloeden. Vaak wordt er een factorypattern-interface aangeboden die je kunt implementeren of kun je een event afvangen dat de aanmaak van nieuwe entries beinvloed.
In 2 seconden kijken zag ik dat de EventFeed klasse een NewAtomEntry event heeft, waar je je eigen handler aan zou kunnen hangen die de EventEntry objecten vervangt door ééntje van het type MyEventEntry.

Het is een long shot, want ik weet niet waar je je klasse gebruikt en of het mogelijk is, maar als je het moment van aanmaken kunt beinvloeden door slim overerven, events afvangen, of een factory-pattern implementeren dan is een derived klasse nog niet zo'n slecht idee.

  • DrDelete
  • Registratie: Oktober 2000
  • Laatst online: 21:50
Ik zie behoorlijk wat activiteit binnen de setter, is dit wel wat je uiteindelijk wilt? Ik zou persoonlijk meer voor een method kiezen dan voor een property (zie de Framework Design Guidelines hierover)

edit:

ff snel wat opgezocht


Use a method when:
  • The operation is a conversion, such as Object.ToString.
  • The operation is expensive enough that you want to communicate to the user that they should consider caching the result.
  • Obtaining a property value using the get accessor would have an observable side effect.
  • Calling the member twice in succession produces different results.
  • The order of execution is important. Note that a type's properties should be able to be set and retrieved in any order.
  • The member is static but returns a value that can be changed.
  • The member returns an array. Properties that return arrays can be very misleading. Usually it is necessary to return a copy of the internal array so that the user cannot change internal state. This, coupled with the fact that a user can easily assume it is an indexed property, leads to inefficient code.
Of check deze link http://msdn2.microsoft.co...rary/bzwdh01d(vs.71).aspx

[ Voor 80% gewijzigd door DrDelete op 07-09-2007 14:00 ]


  • T_E_O
  • Registratie: Oktober 1999
  • Laatst online: 26-11 10:19
Wat __fred__ zegt klinkt leuk. Zo had ik 't nog niet bekeken. Volgens mij moet het best lukken om inderdaad een handler aan dat NewAtomEntry-event toe te voegen. De handler krijgt het nieuwe Event mee in FeedParserEventArgs.Entry, dus dat kan misschien gewoon vervangen worden door een MyEventEntry.

Alhoewel ik dan wederom zit met het feit dat het object al gecreëerd is, dus dan zou ik alsnog alle properties van die EventEntry moeten overnemen in mijn MyEventEntry-object. Verderop in de code kan ik dan wel gewoon MyEventEntry-objecten uit de Events-collectie pakken. Of dat dan gecast wordt naar een EventEntry, doordat de code nog niet up-to-date is daar, dat maakt niet uit, omdat dat een base class is van MyEventEntry, hmmm...

Probleem blijft 't overnemen van alle data uit 'n EventEntry-object in een MyEventEntry-object. Ik ga 's kijken naar 't factory-pattern. Ben een beetje kwijt wat dat was, dus even inlezen.
DrDelete schreef op vrijdag 07 september 2007 @ 13:04:
Ik zie behoorlijk wat activiteit binnen de setter, is dit wel wat je uiteindelijk wilt? Ik zou persoonlijk meer voor een method kiezen dan voor een property (zie de Framework Design Guidelines hierover)
Bedankt! Ik rommel altijd maar wat aan, waardoor bij mij de keuze tussen een property of een method vaak afhangt van m'n humeur, het tijdstip van de dag en of het wel of niet regent. Ik heb op MSDN wat guidelines gevonden waarin ook precies dit onderwerp behandeld wordt. Ik ga even lezen :)

  • __fred__
  • Registratie: November 2001
  • Laatst online: 29-11 20:34
T_E_O schreef op vrijdag 07 september 2007 @ 13:38:
Alhoewel ik dan wederom zit met het feit dat het object al gecreëerd is, dus dan zou ik alsnog alle properties van die EventEntry moeten overnemen in mijn MyEventEntry-object. Verderop in de code kan ik dan wel gewoon MyEventEntry-objecten uit de Events-collectie pakken. Of dat dan gecast wordt naar een EventEntry, doordat de code nog niet up-to-date is daar, dat maakt niet uit, omdat dat een base class is van MyEventEntry, hmmm...

Probleem blijft 't overnemen van alle data uit 'n EventEntry-object in een MyEventEntry-object. Ik ga 's kijken naar 't factory-pattern. Ben een beetje kwijt wat dat was, dus even inlezen.
kijk eens naar deze method:

http://code.google.com/ap....AtomEntry.CopyEntry.html
Pagina: 1