Професионална програма
Loading...
+ Нов въпрос
ttitto avatar ttitto 1154 Точки

[Homework] OOP - Delegates and events - Септември 2014

Здравейте! Качвам ви и най-трудното (вероятно в целия курс) домашно и наистина очаквам да видя още няколко решения и да стане голяма дискусия. Имам чувството, че този патърн на Microsoft още 10 пъти да го уча пак няма да го разбера.

InterestCalculator - Не много трудна задача. Използвах делегата като параметър в конструктора на класа InterestCalculator, за да може да му се подава необходимия метод. Резултатът от извикания метод присвоявам на поле в конструктора.

AsynchronousTimer 

 StudentClass - реших я с generic наследник на EventArgs, но накрая се оказа, че няма смисъл. Мисля да я оставя така, защото не ми се променя отново.

Тагове:
15
C# OOP Basics 26/09/2014 23:42:42
ZvetanIG avatar ZvetanIG 917 Точки

Да задачите наистита са интересни. Бих казал, че не са толкова трудни, а просто нещо ново, с което за пръв път се сблъскваме.

Получиха се доста стегнати решения.

Ето и домашното:

1. Interest Calculator

2. Asynchronous Timer  - доста интересна. По нея падна четене и в крайна сметка се получи добре. (поне аз така си мисля laughing)

3. Student Class -  с половин ден родилни мъки се появи работещо решение и на тази задача. Дали е добре написано незнам...frown

 

11
26/09/2014 14:09:08
oconne avatar oconne 113 Точки

   Първата задача и Тито и Цветан сте я претупали малко. Би трябвало да се сложи едно допълнително поле за класа(Calcul....), което да държи типа на делегата, иначе при повторно използване на обекта за някви цели, няма да имаме правилно изчисление на Интереса. (трябва на ново да използваме конструктур иначе). 

  Втората задача сте я решили доста процедурно, аз съм използвал двойно делегиране и класа Timer, по мързеливо е и по приятно.

Иначе много ми харесаха двете различни концепции които демоснстрирахте. Плюс моят варянт си имаме 3 варянта на втора задача.

Домашното(1 и 2 задача).

Тито не разбрах точно в коя област имаш пропуски, но мисля че си прав че темата с делегирането някак си се подценява. 

4
ZvetanIG avatar ZvetanIG 917 Точки

Колега, относно първа задача, просто сме спазили условието.  Там се иска да има в конструктора делегат и ние сме сложили делегат. Дали е най-умното нещо не съм се замислял.

0
27/09/2014 20:14:51
oconne avatar oconne 113 Точки

Извинявай ако некоректно съм коментирал. Понеже ти си от хората с бързи и качествени идеи (Тито също) си позволих да коментирам (градивно разбира се),  но технически това което си направил е нереализуемо. (Тито също ) Мисля че  е задължително да се спази тоя момент колкото и досаден да е. Нещо или трябва да работи коректно или да хвърля грешка, много се повтори тая фраза на лекциите и мисля че има защо. :) Не мисля че правенето на анализ е заявка за остроумие, а заявка просто за мислене. 

Sorry пак. 

 

0
27/09/2014 21:31:32
dsmiteva avatar dsmiteva 13 Точки

Здравей,

 

private decimal sum;
private double interest;
private int years;
private decimal interestCalculation;
private CalculateInterest typeOfCalculation;


public CalculateInterest TypeOfInterest {

get { return this.TypeOfInterest; }
set {this.typeOfCalculation=value; }
}

 

това пропърти не трябва ли да се казва TypeOfCalculation и в гета да връщаш this.typeOfCalculation? Кода се компилира по този начин, но ако искаш да достъпиш пропъртито както си го именувал гърми рънтайм :)

1
borislavml avatar borislavml 368 Точки

Много интересна материя, и наистина трудна. Но ако се пише софтуеър за юзъри (а има ли някакъв друг?) няма начин, трябва да се научат нещата. Доколлота съм разглеждал JavaScript  библиотеки там всичко живо е event-handlers, така че предполагам в следвашия курс ше имаме възможност подробно да научим ивентите. Ето и моите решения:

Interest Calculator - тук не можах да разбера какво точно трябва да се подава в конструктора: стринг, който да отговаря за даден метод, или делегат. Да се  подава стринг наистина е може би по-юзърфрендли, но класа си го ползваме ние, така че го направих с делегат директно да му се подава. Малко се застрелях в крака като набутах методите за проста и сложна лихва в отделен статичен клас, но пък е по-подредено така. 

Asynchronous timer -  тук реално не съм ползвал ивенти, зашото не можах да видя смисъл... какво да викам с ивента? нали в методa мога да си сожа и таймер-брояч, и всичко.... Но също така неразбрах и какво означава изискването в условието "Тhe main program's executioн should not be paused at any time" WTF?  Демек ако има друг код между редовете в мейн метода да се изпълнява едновременно с брояча ли??? Какво би трябвало да означава изобщо асинхронен таймер. Така, че най-вероятно не съм изпълнил изискването тук.Някой да разсясни по-подробно като на малко дете, ако има време и желание. smile

Student Class- най-интересната задача. Бая се измъчих и почти на магия я направих. Демек работи, ама не съм сигурен защо. Какво имам в предвит: В началото  си напрвах конструктора да може да съзъздава нови студенти без име и възраст с цел после да правя проверка в пропъртито дали като се асайнва име(години) е за първи път (т.е дали this.name == null) и ако е така да не правя нотификейшън за промяна, защото такава реално не е правена . Да, ама не, тая проверка в пропърти сетъра така и не можах да я подкарам. Нешо повече, не можах да направя и проверка дали новто име(годинни) value е различно от текущото this.Name и тогава да си направя new PropertyChangedEventArgs(). Oказва се, че някак си тази проверка пропъртито я прави само за мен и директно си набих в сетъра новите данни в конструктора на PropertyChangedEventArgs. Верно задачата върви, ама... Защо? Дебъгера и той мълчи, гледам го като теле как прескача из кода. smile

 

8
27/09/2014 17:09:39
oconne avatar oconne 113 Точки

Точно така, правилно си разбрал.  Асинхронен брояч  е когато е пуснат и никое друго действие да не го спира (по изключение), и се използват Threading както са направили колегите  по горе. В лекцията на Наков най на края той говори за това.  Така че коментара който правиш е важен и полезен. Всъщност Тimera na Microsft tой казва че е асинхронен (използва трендове в себе си), така че варянта който съм дал май е верен.

2
28/09/2014 11:34:49
arsoman avatar arsoman 419 Точки

Здравейте колеги! Пиша в този пост на колегата, тъй-като ми е чудно решението му. Искам и да споделя нещо с вас, дали ми се струва, или наистина съвсем вече ни претупват, тъй-като изобщо не ми е ясно този метод:

protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs changedArgs)
{
// check if we have subscribers for the event
if (PropertyChanged != null)
{
// trigger the event
PropertyChanged(this, changedArgs);
}
}

какво точно прави, също така не мисля, че на лекцията нещата бяха обяснени в детайлите, които виждам тук. Явно все повече ще се бърза, но нека поне материята се преподаде добре, защото с тези събития нещата са много мътни и необяснени според мен, също така няма как да напиша такъв метод, след като не знам как се управляват, пускат или каквото там тези събития! Иначе сега ще видя решението, но при тези обстоятелства трудно ще го разбера, понеже съвсем малко неща са обяснени. Вярно, че съм онлайн, но имам 4.99 от първото ниво и съм много надъхан да уча и работя, не искам да ни претупват просто набързо и хайде на изпит с непознати неща. Ако може колега да обясниш малко по-подробно решението на трета задача, просто наблегни на тези събития и как се връзват с класовете. Благодаря ти много!

PS: може да се свържем и по скайп, да не досаждаме на другите, ако им е ясно....

1
28/09/2014 19:23:26
borislavml avatar borislavml 368 Точки

Привет колега, ше се опитам да обясня какво се случва в задачата доколкото мога, защото и на мен не са ми ясни нещата колкото ми се иска. 

В началото, когато създаваме делегата public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs eventArgs); към който ще връзваме ивента казваме, че задължително всеки ивент и методите коите реагират на него ще приемат като аргументи sender: обекта, който ни изпраща съобщения за нaстъпил ивент (в случая обекта студент), и eventArgs аргумент, в който се пазят промените (в случая нов обек от класа PropertyChangedEventArgs).

След това си зъздаваме ивент  public event PropertyChangedEventHandler PropertyChanged, който е вързан за делегата (ивент-хендлъра).

В пропърти сетъра на Name и Age когато има направена промяна на this.Name си създаваме нов обект от класа PropertyChangedEventArgs, в който запазваме отразените промени. (this.changedArgs = new PropertyChangedEventArgs("Name", this.Name, value);

Методът, който отговаря за съобщаване абонатие на евента за настъпил такъв също трябва да отговаря на сигнатурата на нашия делегат демек да приема като параметри обект sender и информация за настъпилата промяна eventArgs. В нашия случай sender e student демек текущия обект this и информацията за промените си я запазихме в this.changedArgs, затова подаваме тези параметри на метода this.OnPropertyChanged(this, changedArgs); 

Защо метода OnPropertyChanged e virtual и protected не мога да ти кажа, в презентацията пише, че трябва да е такъв и такъв го правяsmile. Продължавайки да следваме сигнатурата на нашия делегат си му подаваме каквото трябва като параметри. С проверката PropertyChanged != null правим проверка дали някой се е абонирал за нашия ивент и иска да бъде известяван. Явно ивента PropertyChanged е някакъв вид обект, към когото някой като се абонира( абноамента става с secondStudent.PropertyChanged ) се пълни с някво инфо. .NET го прави за нас и не ме интересува как се случва. Ако ивента не е празен и имаме абонати старитаме метода: PropertyChanged(this, changedArgs);

След това в тест класа, след като подаваме абонаметн за заявка от името на secondStudent примерно, със ламбда експрешъни задействаме метода PropertyChanged() , което се случва чрез израза (sender, eventArgs) =>, който е анонимен метод но както виждаш продължава да следва сигнатурата на делегата. Слд това си изкарваме всичко на конзолата, като взимаме пропъртитата на нашия changedArgs.

Надявам се успях да внеса поне малко светлина, защото и аз трудно сам се разбирам понякога, камоли да обясня нещо на някой.

Според мен така работят нещата, ако някой колега е по на ти и вижда грешки в рзмишленията ми да казва smile

P.S. В ООП курса на Telerik от Януари има много хубави и дълги лекции с прекрасни обяснения ЦЪК

А този пич съшо много добре обясняв делегатите и евентите в това видо, лично аз от там ги разбрах.

14
28/09/2014 20:14:37
Ventsislav avatar Ventsislav 343 Точки

Благодаря на колегите споделили решенията си , аз съм новак в ООП и все още ми е малко трудно. Това съчиних с помощ от други решения.

2
d.georgiev.91 avatar d.georgiev.91 63 Точки

Направи ми впечатление, че всичките домашни, които сте качили до момента в класа PropertyChangedEventArgs (от 3та задача) се използват грешни типове за newValue и oldValue или се hardcode-ват oldName, oldAge и т.н. Това не е най-оптималният вариант, защото се получава излишен coupling (явно Наков все още не я е водил тази лекция).

Представете си че след време имате клас File с полета като Size, Attributes, Location, CreatedOn и т.н. И поради някаква причина искате да има event PropertyChanged. 

Първият вариант с подаването на аргументите като string до някъде ще мине, но какво ще стане ако класа Attributes няма метод ToString(), или нека е по-абстрактно ако имате поле Bites, което Byte Array, за което просто няма смисъл да се имплементира ToString()? Ще се получи едно излишно парсване на данни и допълнителна работа, която би могла да бъде спестена.

Вторият вариянт със hardcode-ването на полетата също не е оптимален, защото ако класа File има 200 свойства, ще трябва да ги добавите всичките и в класа PropertyChangedEventArgs и не би било приятна работа.

За да избегнете тази ситуация, може да зададете типoвете на newValue и oldValue да бъдат object. По този начин ще си запазите максимално оригиналните обекти и ще може да ги присвоите само с едно cast-ване.

Да кажем, че има следната истуация - искате поради някаква причина да backup-вате всяка промяна на байтовете на файла. Това може да стане много лесно със следния код:

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
File file = new File(@"C:\report.xls");

file.PropertyChanged += (sender, e) =>
{
if(e.Name == "Bytes") { BackUpFileFromBiteArrayy((byte[])e.OldValue); } }; file.Bytes[124] = 16;

Понеже PropertyChangedEventArgs.Name е уникално за целия клас File, може да се разчита, че ще се хване свойството, което ви трябва и без притеснения, че ще изгърми може да се cast-не към съответния тип (в случая byte[])и да се обработи. Това е причина и sender да е object.

 

5
Dzhuliya avatar Dzhuliya 5 Точки

Здравейте, колеги!

Тъй като закъснях с изпращането на домашното, бих се радвала да получа някакъв фийдбек по първата задача (че засега до там съм стигнала) :)

Ето го и кода ми

0
02/10/2014 17:44:08