I want an event notification system that should notify the doctor when the heartbeat of the patient is greater than 120.I do not know, How to design such system. Just I have implemented the wrong one. Help me in implementing the correct one.
static void Main()
{
Patient[] patList = { new Patient
{ PatientID = "1", HeartBeat = 100 },
new Patient { PatientID = "2", HeartBeat = 130 } };
List<Patient> plist = patList.ToList();
Console.ReadKey(true);
}
public class Doctor
{
public event PulseNotifier AbnormalPulseRaised;
public string Name
{
get;
set;
}
}
public class Patient
{
public event PulseNotifier AbnormalPulseRaised;
static Random rnd = new Random();
public Patient()
{
PulseNotifier += new PulseNotifier(OnAbnormalPulseRaised);
}
public string PatientID
{
get;
set;
}
public int HeartBeat
{
get;
set;
}
public void HeartBeatSimulation(List<Patient> patList)
{
foreach(Patient p in patList)
{
if (p.HeartBeat > 120)
{
if (AbnormalPulseRaised != null)
{
AbnormalPulseRaised(p);
}
}
}
}
public void OnAbnormalPulseRaised(Patient p)
{
Console.WriteLine("Patient Id :{0},Heart beat {1}",
p.PatientID, p.HeartBeat);
}
}
Apart from that, I want to have a common clarification.
What is the best way to remember the publisher and observer pattern?. Because I am quite confusing about where to implement publisher and where to implement
Well, for starters, I usually think it's an bad Idea to listen to the events of a class in the same class if you have access to it.
It's also a good idea to derive from EventArgs, which is recommended by MS.
The responsibility of raising the event should indeed be in the patient class itself, but here you raise only the event of the class where you call the HardBeatSimulation function itself instead of on the patient that actually has an abnormal pusle :)
static void Main(string[] args) {
Patient pat1 = new Patient(1, 120);
Patient pat2 = new Patient(3, 150); // this one can have a 150 bpm hartbeat :)
Doctor fancyDoctor = new Doctor();
fancyDoctor.AddPatient(pat1);
fancyDoctor.AddPatient(pat2);
Console.ReadKey(true);
}
public class Doctor {
List<Patient> _patients;
public event EventHandler Working;
public Doctor() {
_patients = new List<Patient>();
}
public void AddPatient(Patient p) {
_patients.Add(p);
p.AbnormalPulses += new EventHandler<AbnormalPulseEventArgs>(p_AbnormalPulses);
}
void p_AbnormalPulses(object sender, AbnormalPulseEventArgs e) {
OnWorking();
Console.WriteLine("Doctor: Oops, a patient has some strange pulse, giving some valium...");
}
protected virtual void OnWorking() {
if (Working != null) {
Working(this, EventArgs.Empty);
}
}
public void RemovePatient(Patient p) {
_patients.Remove(p);
p.AbnormalPulses -= new EventHandler<AbnormalPulseEventArgs>(p_AbnormalPulses);
}
}
public class Patient {
public event EventHandler<AbnormalPulseEventArgs> AbnormalPulses;
static Random rnd = new Random();
System.Threading.Timer _puseTmr;
int _hartBeat;
public int HartBeat {
get { return _hartBeat; }
set {
_hartBeat = value;
if (_hartBeat > MaxHartBeat) {
OnAbnormalPulses(_hartBeat);
}
}
}
protected virtual void OnAbnormalPulses(int _hartBeat) {
Console.WriteLine(string.Format("Abnormal pulsecount ({0}) for patient {1}", _hartBeat, PatientID));
if (AbnormalPulses != null) {
AbnormalPulses(this, new AbnormalPulseEventArgs(_hartBeat));
}
}
public Patient(int patientId, int maxHartBeat) {
PatientID = patientId;
MaxHartBeat = maxHartBeat;
_puseTmr = new System.Threading.Timer(_puseTmr_Tick);
_puseTmr.Change(0, 1000);
}
void _puseTmr_Tick(object state) {
HartBeat = rnd.Next(30, 230);
}
public int PatientID {
get;
set;
}
public int MaxHartBeat {
get;
set;
}
}
public class AbnormalPulseEventArgs : EventArgs {
public int Pulses { get; private set; }
public AbnormalPulseEventArgs(int pulses) {
Pulses = pulses;
}
}
The method OnAbnormalPulseRaised(Patient p) should be placed in Doctor class because doctor is the one being notified about event. The event property should by placed in Patient class because patients are raising the events:
public class Doctor
{
public Doctor()
{
// doctor initialization - iterate through all patients
foreach(patient in patList)
{
// for each patient register local method as event handler
// of the AbnormalPulseRaised event.
patient.AbnormalPulseRaised +=
new PulseNotifier(this.OnAbnormalPulseRaised);
}
}
public void OnAbnormalPulseRaised(Patient p)
{
Console.WriteLine("Patient Id :{0},Heart beat {1}",
p.PatientID, p.HeartBeat);
}
public string Name
{
get;
set;
}
}
public class Patient
{
public event PulseNotifier AbnormalPulseRaised;
static Random rnd = new Random();
public Patient()
{
}
public string PatientID
{
get;
set;
}
public int HeartBeat
{
get;
set;
}
public void HeartBeatSimulation(List<Patient> patList)
{
foreach(Patient p in patList)
{
if (p.HeartBeat > 120)
{
if (AbnormalPulseRaised != null)
{
AbnormalPulseRaised(p);
}
}
}
}
}
Publisher is the object with event property. Subscriber is the object with handler method.
Related
I have currently a problem
I have 1 Interface with two types of argument like this
ITestInterface<ArgumentA>
ITestInterface<ArgumentB>
this interface has only the argument as different
I would like to pass this interface to an constructor of a class. sth like this
public class MyClass
{
public ITestInterface<object> MyInterface {get; set;}
public MyClass(ITestInterface<ArgumentA> testInterfaceA){
this.MyInterface = testInterfaceA as ITestInterface<object>;
this.MyTestInterface.SomeEvent += this.OnSubcribe;
}
public MyClass(ITestInterface<ArgumentB> testInterfaceB){
this.MyInterface = testInterfaceB as ITestInterface<object>;
this.MyTestInterface.SomeEvent += this.OnSubcribe;
}
public void OnSubcribe(){
//Work to do here, dont care about what argument the interface has.
}
}
and to call the MyClass constructor I have sth like this:
public List<MyClass> ClassList = new();
public void testMethod(){
var interA = getInterfaceWithArgumentA();
var myClassA = new MyClass(interA);
var interB = getInterfaceWithArgumentB();
var myClassB = new MyClass(interB);
}
So the problem is i am not able to cast the interface argument to object. I dont need to differenciate the argument either. I just want to avoid to have 2 properties of MyInterface like (MyInterfaceA, MyInterfaceB).
I need also to consider that maybe in the future I will have more type of Argument so maybe to have multiple properties like MyInterfaceA, MyInterfaceB, MyInterfaceC and also multiple constructor for each Interfaceargument type would be a mess.
I just thought about have a Baseclass and the ArgumentA and ArgumentB class derived from it so the cast would work but its not like that.
How would I solve this problem ?
Many Thanks
I think you have not provided what getInterfaceWithArgumentB() and getInterfaceWithArgumentA() method doing. I am making few assumption.
To solve your problem Generic will help.
Following is the example of it.
public class MyClass<T>
{
public ITestInterface<T> MyInterface { get; set; }
public MyClass(ITestInterface<T> testInterfaceA)
{
this.MyInterface = testInterfaceA;
this.MyInterface.SomeEvent += MyInterface_SomeEvent;
}
private void MyInterface_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}
public class ArgumentA
{
public string Name { get; set; }
}
public class ArgumentB
{
public int Id { get; set; }
}
public interface ITestInterface<T>
{
T Data { get; set; }
event EventHandler SomeEvent;
void OnSomeEvent();
}
public class TestInterface<T> : ITestInterface<T>
{
public T Data { get ; set; }
public event EventHandler SomeEvent;
public void OnSomeEvent()
{
if(SomeEvent != null)
SomeEvent(Data, EventArgs.Empty);
}
}
You can use it like following.
MyClass<ArgumentA> myClass = new MyClass<ArgumentA>(
new TestInterface<ArgumentA>()
{
Data = new ArgumentA() { Name = "test" }
});
MyClass<ArgumentB> myClas2 = new MyClass<ArgumentB>(
new TestInterface<ArgumentB>()
{
Data = new ArgumentB() { Id = 10 }
});
myClas2.MyInterface.OnSomeEvent();
myClass.MyInterface.OnSomeEvent();
UPDATE
class Program
{
static void Main(string[] args)
{
ObservableCollection<MyClass> items = new ObservableCollection<MyClass>();
MyClass<ArgumentA> myClass = new MyClass<ArgumentA>(
new TestInterface<ArgumentA>()
{
Data = new ArgumentA() { Name = "test" }
});
MyClass<ArgumentB> myClas2 = new MyClass<ArgumentB>(
new TestInterface<ArgumentB>()
{
Data = new ArgumentB() { Id = 10 }
});
items.Add(myClass);
items.Add(myClas2);
myClas2.MyInterface.OnSomeEvent();
myClass.MyInterface.OnSomeEvent();
}
}
public class MyClass
{
public ITestInterface MyInterface { get; set; }
}
public class MyClass<T> : MyClass
{
public MyClass(ITestInterface<T> testInterfaceA)
{
this.MyInterface = testInterfaceA;
this.MyInterface.SomeEvent += MyInterface_SomeEvent;
}
private void MyInterface_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}
public class ArgumentA
{
public string Name { get; set; }
}
public class ArgumentB
{
public int Id { get; set; }
}
public interface ITestInterface
{
event EventHandler SomeEvent;
void OnSomeEvent();
}
public interface ITestInterface<T> : ITestInterface
{
T Data { get; }
}
public class TestInterface<T> : ITestInterface<T>
{
public T Data { get; set; }
public event EventHandler SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent(Data, EventArgs.Empty);
}
}
This is the first time I am getting NZEC error. I don't understand this error, I just found that it stands for "Non Zero Exit Code". But what does this means. When we get this error. I am getting this error on one of online coding challenge websites and not in Visual Studio.
I am real need of help. Please check following code snippet where I am getting this error and please suggest what I am doing wrong.
using System;
using System.Collections.Generic;
using System.Linq;
namespace PractiseConsoleApplication
{
internal class Program
{
private static void Main(string[] args)
{
//Get input
var stringInput = Console.ReadLine();
var numberOfRooms = Convert.ToInt32(Console.ReadLine());
var endOfInput = Convert.ToInt32(Console.ReadLine());
var customers = stringInput.ToArray();
var hotel = new Hotel(numberOfRooms);
foreach (var customerName in customers)
{
hotel.CheckInCheckoutCustomer(customerName);
}
Console.WriteLine(Convert.ToString(hotel.CustomersLeftWithoutStayingInHotel.Count));
}
}
internal class Hotel
{
public bool IsRoomAvailable { get; private set; }
public List<HotelRoom> Rooms { get; private set; }
public List<char> CustomersLeftWithoutStayingInHotel { get; private set; }
private Hotel()
{
Rooms = new List<HotelRoom>();
CustomersLeftWithoutStayingInHotel = new List<char>();
}
public Hotel(int numberOfRooms)
: this()
{
for (int i = 1; i <= numberOfRooms; i++)
{
Rooms.Add(new HotelRoom(i));
}
}
public void CheckInCheckoutCustomer(char customer)
{
if (CustomersLeftWithoutStayingInHotel.Any(f => f == customer))
{
return;
}
var existingCustomer = Rooms.FirstOrDefault(f => f.IsRoomAllocatedToCustomer && f.CustomerName == customer);
//Already room allocated to this customer
if (existingCustomer != null)
{
//checkout him
existingCustomer.CustomerCheckout();
}
else
{
//Get empty rooms
var emptyRoom = Rooms.FirstOrDefault(f => f.IsRoomAllocatedToCustomer == false);
if (emptyRoom != null)
{
emptyRoom.AllocateRoomToCustomer(customer);
}
else
{
CustomersLeftWithoutStayingInHotel.Add(customer);
}
}
}
}
internal class HotelRoom
{
public int RoomNumber { get; private set; }
public char? CustomerName { get; private set; }
public HotelRoom(int roomNumber)
{
RoomNumber = roomNumber;
CustomerName = null;
}
public bool IsRoomAllocatedToCustomer
{
get
{
return CustomerName.HasValue;
}
}
public void AllocateRoomToCustomer(char customerDetails)
{
CustomerName = customerDetails;
}
public void CustomerCheckout()
{
CustomerName = null;
}
}
internal class Customer
{
public char CustomerName { get; private set; }
public Customer(char name)
{
CustomerName = name;
}
}
}
as Tony Hopkinson says in the comments, main should return an int.
place this statement in the end of main method:
return 0;
this will exit with zero code(thus the Non Zero Exit Code error)
i am working on a small app that mange flights, i have a class that build a flight details and class that build the passenger, now, i want to load the passengers onto a flight, how should i do it? do i need to build a higer class that inherit from this two class and make a list of that type of class(i dont think that wise oop ).or should i add a ticket prop in the passenger class that have the flight number, here is my code.
public class Passenger
{
public Passenger(string name, int passportNumber)
{
this.PassengerName = name;
this.PassportNumber = passportNumber;
}
private string _passengerName;
public string PassengerName
{
get { return _passengerName; }
set { _passengerName = value; }
}
private int _passportNumber;
public int PassportNumber
{
get { return _passportNumber; }
set { _passportNumber = value; }
}
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
this.FlightNumber = flightNumber;
this.FlightDestination = flightDestination;
this.PlanModel = planmodel;
}
private int _flightNumber;
public int FlightNumber
{
get { return _flightNumber; }
set { _flightNumber = value; }
}
private string _flightDestination;
public string FlightDestination
{
get { return _flightDestination; }
set { _flightDestination = value; }
}
private string _planeModel;
public string PlanModel
{
get { return _planeModel; }
set { _planeModel = value; }
}
}
static void Main(string[] args)
{
List<FlightDetails> flightList = new List<FlightDetails>();
FlightDetails a = new FlightDetails(12,"france","jumbo");///create a flight
flightList.Add(a);/// load up the flight
}
First, you can't create a class that inherits from both other classes because multiply inheritance is not allowed in C#.
You can use aggregation, something like this:
public class FlightDetails
{
// ...
}
public class Passenger
{
// ...
}
public class Flight
{
public FlightDetails { get; private set; }
public List<Passenger> Passengers { get; private set; }
public Flight(FlightDetails details)
{
FlightDetails = details;
Passengers = new List<Passenger>();
}
public AddPassenger(Passenger p)
{
// check for ticket and so on..
Passengers.Add(p);
}
}
You can read more about aggregation here: http://en.wikipedia.org/wiki/Object_composition#Aggregation
Note that in this example for simplicity i used List but actually you need to limit access to this array (because otherwise i can do something like this: Flight.Passengers.Add(p) instead of Flight.AddPassenger(p)) so good idea will be use ReadOnlyCollection as public interface to this list.
Here's a sample code that might work. A flight has one or more passengers, thus has a List of type Passenger. In real-life, a passenger can book multiple flights. If you want the reality, you'll have to change your model but for this situation it'll work:
public class Passenger
{
public Passenger(string name, int passportNumber)
{
PassengerName = name;
PassportNumber = passportNumber
}
public string PassengerName { get; set; }
public int PassportNumber { get; set; }
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
Passengers = new List<Passengers>();
}
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public List<Passenger> Passengers { get; private set; }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = Passengers.Count;
if (passengersNumber < max)
{
Passengers.Add(new Passenger(name, number);
}
}
public static void Main(string[] args)
{
var flightList = new List<FlightDetails>();
var passengersList = new List<Passenger>();
//Add passenger-objects to passengers-list
var flightOne = new FlightDetails(12, "France", "Jumbo");
flightOne.Passengers = passengersList;
flightList.Add(a);
}
Here's a better solution to limit the passengers:
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
: this(flightNumber, flightDestination, planmodel, new List<Passenger>())
{
}
public FlightDetails(int flightNumber, string flightDestination, string planmodel, List<Passenger> passengers)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
if(passengers.Count > 2)
//throw exception or error
else
_passengers = passengers;
}
private List<Passenger> _passengers = new List<Passenger>();
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public IEnumerable<Passenger> Passengers { get { return _passengers; } }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = _passengers.Count;
if (passengersNumber < max)
{
_passengers.Add(new Passenger(name, number);
}
}
}
Note: this code is written without compiling. But the idea is correct normally. :)
In logical way, relation between FlightDetail to Passenger is OneToMany. One FlightDetail can have multiple Passenger which is can be written as below. FlightDetail and Passenger should be have any common inheritance hierarchy because they are don't have any common attribute or behaviour.
public class FlightDetails
{
private List<Passenger> passengerList;
public void addPassenger(Passenger p){
if(passengerList == null){
passengerList = new ArrayList<Passenger>();
}
passengerList.add(p);
}
public List<Passenger> getPassengerList(){
return passengerList;
}
//... your other detail
}
You should add a FlightDetails property to your Passenger class. That's easier than making a List with PassportNumber as index. But, it's easier to iterate FlightDetails using List, than accessing it through Passenger.
It actually depends on how you want to access and store the relations.
It might be a good idea to read about the composite pattern which actually has a nice solution for travelling between parent-child relations, even though the pattern has another purpose.
I have implemented Single Pattern. Here is my code i am getting the an error when i call the Test.BuildData() function. Please help
public class WordDataItem
{
public string Word { get; set; }
public string Definition { get; set; }
public int WordGroupKey { get; set; }
}
public class WordDataGroup
{
public List<WordDataItem> listItem = new List<WordDataItem>();
public int GroupKey { get; set; }
}
public sealed class WordDataSource
{
private static WordDataSource _dataSoruce;
private List<WordDataGroup> listGroup = new List<WordDataGroup>();
public List<WordDataGroup> ListGroup
{
get { return listGroup; }
set { listGroup = value; }
}
private WordDataSource() { }
public static WordDataSource Instance
{
get
{
if (Instance == null)
{
_dataSoruce = new WordDataSource();
}
return _dataSoruce;
}
}
}
public static class Test
{
public static void BuildData()
{
WordDataSource.Instance.ListGroup.Add(new WordDataGroup() { GroupKey = 8, listItem = new List<WordDataItem>() { new WordDataItem() {Word = "Hello", Definition="Greetings", WordGroupKey = 8}} });
}
}
I get an error of stack over flow when i call the Test.BuildData() function.
Your Instance property is recursively calling into itself when you check if it is null.
Try this:
public static WordDataSource Instance
{
get
{
if (_dataSoruce == null)
{
_dataSoruce = new WordDataSource();
}
return _dataSoruce;
}
}
The following code is a silverlight application but the same happens in WPF, so it seems to be just something I'm missing regarding the delegate, event, etc.
Can anyone tell me why the following code successfully executes this event:
OnLoadingComplete(this, null);
but never executes this event handler?
void initialDataLoader_OnLoadingComplete(object obj, DataLoaderArgs args)
CODE:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Diagnostics;
namespace TestEvent22928
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataLoader initialDataLoader = new DataLoader("initial");
initialDataLoader.RegisterText("test1", "http://test:111/testdata/test1.txt");
initialDataLoader.RegisterText("test2", "http://test:111/testdata/test2.txt");
initialDataLoader.BeginLoading();
initialDataLoader.OnLoadingComplete += new DataLoader.LoadingComplete(initialDataLoader_OnLoadingComplete);
}
void initialDataLoader_OnLoadingComplete(object obj, DataLoaderArgs args)
{
Debug.WriteLine("loading complete"); //WHY DOES EXECUTION NEVER GET HERE?
}
}
public class DataManager
{
public DataLoader CreateDataloader(string dataloaderIdCode)
{
DataLoader dataLoader = new DataLoader(dataloaderIdCode);
return dataLoader;
}
}
public class DataLoader
{
public string IdCode { get; set; }
public List<DataItem> DataItems { get; set; }
public delegate void LoadingComplete(object obj, DataLoaderArgs args);
public event LoadingComplete OnLoadingComplete = delegate { };
private int dataItemCurrentlyLoadingIndex;
public DataLoader(string idCode)
{
IdCode = idCode;
DataItems = new List<DataItem>();
dataItemCurrentlyLoadingIndex = -1;
}
public void RegisterText(string idCode, string absoluteSourceUrl)
{
DataItem dataItem = new DataItem
{
IdCode = idCode,
AbsoluteSourceUrl = absoluteSourceUrl,
Kind = DataItemKind.Text
};
DataItems.Add(dataItem);
}
public void BeginLoading()
{
LoadNext();
}
private void LoadNext()
{
dataItemCurrentlyLoadingIndex++;
if (dataItemCurrentlyLoadingIndex < DataItems.Count())
{
DataItem dataItem = DataItems[dataItemCurrentlyLoadingIndex];
Debug.WriteLine("loading " + dataItem.IdCode + "...");
LoadNext();
}
else
{
OnLoadingComplete(this, null); //EXECUTION GETS HERE
}
}
}
public class DataItem
{
public string IdCode { get; set; }
public string AbsoluteSourceUrl { get; set; }
public DataItemKind Kind { get; set; }
public object DataObject { get; set; }
}
public enum DataItemKind
{
Text,
Image
}
public class DataLoaderArgs : EventArgs
{
public string Message { get; set; }
public DataItem DataItem { get; set; }
public DataLoaderArgs(string message, DataItem dataItem)
{
Message = message;
DataItem = dataItem;
}
}
}
You're registering the handler only after you start loading:
initialDataLoader.BeginLoading();
initialDataLoader.OnLoadingComplete += new DataLoader.LoadingComplete(initialDataLoader_OnLoadingComplete);
The way your code is currently written, it looks like BeginLoading() blocks until completion, which means the handler will never be called, as you don't set it until after you've finished loading.