Memory simulation in WPF: Binding byte array positions - c#

I'm writing a language interpreter using C#. My user interface permits to visualize and change global variables and direct memory addresses in runtime.
I have problems when I try to visualize and change direct memory addresses as they can be visualized in different data sizes (BYTE, WORD and DWORD).
0 1 2 3
---------------------------------
| FFx16 | FFx16 | FFx16 | FFx16 | Memory
---------------------------------
- BYTE 3-
---- WORD 1 -----
------------ DWORD 0 ------------
So, If I'm visualizing BYTE3, WORD1 and DWORD0 in my UI, when I change value of BYTE3 my view doesn't upgrade WORD1 and DWORD0 values.
Memory and execution context (Model):
public class Memoria
{
private byte[] memoria;
public Memoria(int size)
{
memoria = new byte[size];
}
public void Write<T>(int index, Tipo t, T value)
{
int nBytes = t.GetBytes();
byte[] bytesArray = t.GetBytesArray(value);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytesArray);
for (int i = 0; i < nBytes; i++)
{
memoria[index+ i] = bytesArray[i];
}
}
}
public class Context
{
public Memoria DataMem { get; set; }
public Dictionary<int, IVariableObservable> VarGlobal { get; private set; }
public Dictionary<int, IVariableObservable> DirectAdress { get; private set; }
public InsertValues ()
{
foreach (IVariableObservable v in VarGlobal.Values)
{
Action action = () => v.Valor = v.InitValue;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, action);
v.InsertValue();
}
}
public UpdateValue (int index)
{
IVariableObservable v = VarGlobal[index];
v.UpdateValue();
}
}
}
// * Language interpreter types are represented in Tipo objects
public abstract class Tipo
{
//* ....... More methods
public virtual int GetBytes()
{
return 0;
}
// * UI Representation
public virtual T GetUIRepresentation<T>(object valor)
{
return (T)Convert.ChangeType(valor, typeof(T));
}
}
Variable (Model):
public interface IVariableObservable : INotifyPropertyChanged
{
string Name { get; }
Tipo Tipo { get; }
object Valor { get; set; }
object InitValue { get; set; }
int Offset { get; set; }
Memoria DataMem { get; set; }
void InsertValue()
void UpdateValue();
void OnPropertyChanged(string propertyName);
}
public interface IVariableObservable<T> : IVariableObservable
{
new T Valor { get; set; }
new T InitValue { get; set; }
}
public class VariableObservable<T> : INotifyPropertyChanged, IVariableObservable<T>
{
private T valor;
public T Valor
{
get
{
return this.valor;
}
set
{
if (value.ToString() == this.valor.ToString())
return;
this.valor = value;
this.OnPropertyChanged("Valor");
}
}
object IVariableObservable.Valor
{
get { return Valor; }
set
{
Valor = Tipo.GetUIRepresentation<T>(value);
}
}
public Memoria DataMem { get; set; }
public void InsertValue()
{
DataMem.Write<T>(Offset, Tipo, Valor);
}
public void UpdateValue()
{
Valor = DataMem.Read<T>(Offset, Tipo);
}
}
My viewmodel:
public class VariableViewModel : WorkspaceViewModel
{
readonly IVariableObservable _variable;
readonly ObserverRepository _observerRepository;
public VariableViewModel(IVariableObservable variable, ObserverRepository observerRespository)
{
if (variable == null)
throw new ArgumentNullException("variable");
if (observerRespository == null)
throw new ArgumentNullException("observerRespository");
_variable = variable;
_observerRepository = observerRespository;
this._variable.PropertyChanged += this.OnVariableValueChanged;
}
private void OnVariableValueChanged(object sender, EventArgs e)
{
this.OnPropertyChanged("Valor");
}
public object Valor
{
get
{
return _variable.Valor;
}
set
{
if (value == _variable.Valor)
return;
_variable.Valor = value;
this.OnPropertyChanged("Valor");
_variable.InsertValue();
}
}
}
Is there any way to check changes in the different memory positions and propagate changes to all memory addresses which share those memory positions?

OK so as discussed in comments I didn't fix your code so much as re-write it entirely to use a different architecture that I think will work better for you assuming it doesn't break other functionality you require.
The main goal of my code was to make it so variables didn't keep copies of their values but instead looked to the memory store itself when retrieving the value and likewise using the memory store to set its value.
All variables store is a 'pointer' to a memory location (an address within a IMemory object). The IMemory object provides Read and Write operations to read and write one or more contiguous bytes from/to the memory.
IMemory exposes a MemoryChanged event which fires whenever a Write operation occurs. Variables attached themselves to this event in their constructor and upon receiving the event they check whether any of the changed addresses cover any part of the variable. If they do then the variable fires its INotifyPropertyChanged event which can be use by WPF et al to monitor for variable updates.
And now the code:
public interface IMemory
{
void Write(int address, params byte[] bytes);
byte[] Read(int address, int numBytes);
byte Read(int address);
event MemoryChangedEventHandler MemoryChanged;
}
public class Memory : IMemory
{
private readonly byte[] _memory;
public Memory(int size)
{
_memory = new byte[size];
}
public void Write(int address, params byte[] bytes)
{
for (int offset = 0; offset < bytes.Length; offset++)
{
_memory[address + offset] = bytes[offset];
}
UpdateMemory(address, bytes.Length);
}
public byte[] Read(int address, int numBytes)
{
return _memory.Skip(address).Take(numBytes).ToArray();
}
public byte Read(int address)
{
return _memory[address];
}
private void UpdateMemory(int address, int length)
{
if (MemoryChanged != null)
{
MemoryChanged(this, new MemoryChangedEventArgs
{
StartAddress = address,
EndAddress = address + length
});
}
}
public event MemoryChangedEventHandler MemoryChanged;
}
public delegate void MemoryChangedEventHandler(object sender, MemoryChangedEventArgs e);
public class MemoryChangedEventArgs
{
public int StartAddress { get; set; }
public int EndAddress { get; set; }
}
public class IntVariable : INotifyPropertyChanged
{
private readonly int _address;
private readonly Memory _memory;
public IntVariable(int address, Memory memory)
{
_address = address;
_memory = memory;
_memory.MemoryChanged += MemoryChanged;
}
private void MemoryChanged(object sender, MemoryChangedEventArgs e)
{
int startAddress = _address;
int endAddress = startAddress + sizeof (int);
int changedStartAddress = e.StartAddress;
int changedEndAddress = e.EndAddress;
if (IsVariableChanged(startAddress, changedStartAddress, endAddress, changedEndAddress))
{
OnPropertyChanged("Value");
}
}
private static bool IsVariableChanged(int startAddress, int changedStartAddress, int endAddress, int changedEndAddress)
{
return Math.Max(startAddress, changedStartAddress) <= Math.Min(endAddress, changedEndAddress);
}
public int Value
{
get
{
var intBytes = _memory.Read(_address, sizeof(int));
return BitConverter.ToInt32(intBytes, 0);
}
set
{
var intBytes = BitConverter.GetBytes(value);
_memory.Write(_address, intBytes);
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
So you would construct your Memory object then create IntVariable (obviously you would create different variable types as required for your different visualisations) objects that reference the Memory object and an address within the memory.
E.g.
var _memory = new Memory(20);
var variable1 = new IntVariable(0, _memory);
var variable2 = new IntVariable(0, _memory);
Then doing variable1.Value = 4; would make variable1 and variable2 fire their INotifyPropertyChanged event.
Hope this is what you were looking for.

Related

How to keep custom object sequence property in model when there are multiple lists of that type used in application

I have a wpf application with MVVM pattern. There is a view which displays the warnings (text) on screen, which are of type WarningModel.cs
In my ViewModel I have 3 properties of type ObservableCollection<WarningModel>(), these are bound to 3 different grids (telerik for wpf grids). Three grids because there are 3 types of warnings.
My requirement is when user adds new warning (new object of type WarningModel) into the grid, that object should be assigned an order sequence starting with 1 followed by 2 and so on for next object.
What I tried is added a static field in Warning.cs which will be auto incremented each time the constructor is called. Now the problem is since there are 3 ObservableCollection each time the object is instantiated from any of the collection, sequence gets incremented but all the three collection should maintain their own sequence.
What else can be employed here to achieve the desired output.
Here are my classes
public class Warning
{
public string MESSAGE { get; set; }
private int _type;
public int TYPE
{
get { return _type; }
set
{
if (value != _type)
_type = value;
}
}
public int SORT_ORDER { get; set; }
public static int SORT_SEQUENCE = 0;
public Warning()
{
SORT_ORDER = Interlocked.Increment(ref SORT_SEQUENCE);
}
}
public class WarningsViewModel
{
public ObservableCollection<WarningModel> WarningBP { get; set; }
public ObservableCollection<WarningModel> WarningPP { get; set; }
public ObservableCollection<WarningModel> WarningPB { get; set; }
public VoyageInfoViewModel()
{
WarningBP = new ObservableCollection<WarningModel>();
WarningPP = new ObservableCollection<WarningModel>();
Warning PB = new ObservableCollection<WarningModel>();
}
}
You can attach handler for CollectionChanged of ObservableCollection and assign ID as index of inserted item.
public VoyageInfoViewModel()
{
WarningBP = new ObservableCollection<WarningModel>();
WarningBP.CollectionChanged += WarningCollectionChanged;
...
}
private void WarningCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
for (var i = 0; i < e.NewItems.Count; i++)
((Warning)e.NewItems[i]).SORT_ORDER = e.NewStartingIndex + i + 1;
}
If you allow user also to delete warnings and want SORT_ORDER be recalculated on deletion you can write handler as:
private void WarningCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
for (var i = 0; i < ((ICollection)sender).Count; i++)
((Warning)((IList)sender)[i]).SORT_ORDER = i + 1;
}
You could for example create a custom ObservableCollection<T> that sets the sequence number of added items. Something like this:
public class SequencedObservableCollection : ObservableCollection<WarningModel>
{
private int _sequenceCounter = 0;
protected override void InsertItem(int index, WarningModel item)
{
item.SORT_ORDER = ++_sequenceCounter;
base.InsertItem(index, item);
}
}
public abstract class WarningModel
{
public int SORT_ORDER { get; set; }
}
Don't forget to change the type of your source properties in the view model:
public SequencedObservableCollection WarningBP { get; set; }
public SequencedObservableCollection WarningPP { get; set; }
public SequencedObservableCollection WarningPB { get; set; }

How distinguish between objects type c#

I am creating a basketball WPF app which displays a HomeTeam and an AwayTeam.
I have created a Player object and in the main window I have created ObservableCollection of player objects for both the home (HomePlayersList) and the away teams (AwayPlayersList). I have used INotifyPropertyChanged interface on the player object so when IsInGame bool is true the player gets added to one of the two ObservableCollection<Player> depending on the count. (If list one ObservableCollection<Player> HomeTeam or ObservableCollection<Player> AwayTeam count is 5, then the rest gets added to the substitution list ObservableCollection<Team> HomeSub or ObservableCollection<Team> AwaySub.)
But I am trying to distinguish whether the player is in the home or away team, and depending on which list the player is in, the player would be added to the new list of home or away.
public static ObservableCollection<Player> HomePlayersList;
public static ObservableCollection<Player> AwayPlayersList;
public static ObservableCollection<Player> HomeTeam = new ObservableCollection<Player>();
public static ObservableCollection<Player> AwayTeam = new ObservableCollection<Player>();
public static ObservableCollection<Player> HomeSub = new ObservableCollection<Player>();
public static ObservableCollection<Player> AwaySub = new ObservableCollection<Player>();
public static int HomeSubCount = 7;
public class Player: INotifyPropertyChanged
{
public static bool IsHome = true;
private static int TotalSelected = 1;
public string Id { get; set; } //player ID
public string FirstName { get; set; } //player first name
public string SecondName { get; set; } //player second name
public string KnownName { get; set; } //player known name
public string Position { get; set; } //player position
public string Number { get; set; } //player number
public bool isInGame;
public bool IsInGame
{
get { return isInGame; }
set
{
if (value != isInGame)
{
isInGame = value;
if (isInGame)
{
OnPropertyChanged("IsInGame", true);
}
else
{
OnPropertyChanged("IsInGame", false);
}
}
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName, bool state)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
if (state)
{
if (TotalSelected > 5 + MainWindow.HomeSubCount)
{
this.IsInGame = false;
return;
}
if (MainWindow.HomeTeam.Count < 5)
MainWindow.HomeTeam.Add(this);
else
{
if (MainWindow.HomeSub.Count < MainWindow.HomeSubCount)
{
MainWindow.HomeSub.Add(this);
}
}
TotalSelected++;
}
else
{
if (SearchForMe(MainWindow.HomeTeam) != null)
{
MainWindow.HomeTeam.Remove(SearchForMe(MainWindow.HomeTeam));
TotalSelected--;
return;
}
if (SearchForMe(MainWindow.HomeSub) != null)
{
MainWindow.HomeSub.Remove(SearchForMe(MainWindow.HomeSub));
TotalSelected--;
return;
}
}
}
private Team SearchForMe(ObservableCollection<Team> OCT)
{
return OCT.Where(i => i.Number == this.Number).SingleOrDefault();
}
public event PropertyChangedEventHandler PropertyChanged;`enter code here`
}
Paste in the Player class a property
ObservableCollection<Player> CurrnetIn { get; set; }
and set this property, if you Add the player in some collection. Or have I misunderstood the question.
You could use the Contains method of the ObservableCollection<T> class to determine whether a specific object is already in the collection:
if (MainWindow.HomeTeam.Contains(this))
{
MainWindow.HomeTeam.Remove(this);
TotalSelected--;
return;
}
Since your Player class doesn't implement the IEquatable<T> interface the references that you pass to the Contains method will be compared to the items in the collection which is totally fine in this case:
Does List<String>.Contains(mystring) do a reference comparison or a value comparison?

Polymorphism and Interfaces in C#

Create three small classes unrelated by inheritance—classes Building, Car and Bicycle. Write an interface ICarbonFootprint with a GetCarbonFootprint method. Have each of your classes implement that interface, so that its GetCarbonFootprint method calculates an appropriate carbon footprint for that class (check out a few websites that explain how to calculate carbon footprints). Write an app that creates objects of each of the three classes, places references to those objects in List, then iterates through the List, polymorphically invoking each object’s GetCarbonFootprint method. Constructor of Car initialize “gallon of gas”, and the Building constructor will initialize buiding-square-footage.
how to calculate carbon-footprint
One gallon of gas yields 20 pounds of CO2 for a car
Multiply the square footage by 50 for a building
None for a bicycle
My instructor's code:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
static void Main(string[] args)
{
Bicycle bike = new Bicycle();
Building b = new Building();
Car car = new Car();
List<ICarbonFootprint> list = new List<ICarbonFootprint>();
list.Add(bike);
list.Add(b);
list.Add(car);
int totalCarbon = 0;
foreach (var item in list)
{
totalCarbon += item.GetCarbonFootprint();
Console.WriteLine("{0} has a footprint of: {1}", item, item.GetCarbonFootprint());
}
Console.WriteLine("Total footprint is: {0}", totalCarbon);
Console.ReadKey();
}
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
Me integrating my instructor's code (lines 12-23 changed AKA class Program was the only thing changed):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
So, replacing my code for class Program with my instructor's code, I received the following errors:
Program.cs(51,23,51,41): error CS1729: 'Miller.Building' does not contain a constructor that takes 1 arguments
Program.cs(52,23,52,34): error CS1729: 'Miller.Car' does not contain a constructor that takes 1 arguments
Now, because the last two days before Spring break were cancelled due to the weather (snow), we weren't able to discuss. My code seems to do what the directions ask, but I would like to get my instructor's code for class Program working with my code. Could someone help me with these errors possibly?
There are a few issues with your code.
First up you need to include the constructors to make the code compile.
For Building this would look like:
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
And for Car this would look like:
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
Next, you're not following the rules for calculating the carbon footprint.
They should be:
//Bicycle
public int GetCarbonFootprint()
{
return 0;
}
//Building
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
//Car
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
Finally, your instructor's code doesn't actually display any results. The code in the for loop should be changed to be Console.WriteLine(list[i].GetCarbonFootprint()); if this is a console app.
So, all up the code should look like this:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
Console.WriteLine(list[i].GetCarbonFootprint());
}
public class Bicycle : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 0;
}
}
public class Building : ICarbonFootprint
{
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
public string Address { get; set; }
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
}
public class Car : ICarbonFootprint
{
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
I've opted to short-cut the property definitions rather than implement them with fields.
The output is:
0
125000
200
You should write constructors for Building and Car like next:
public Building(int MyValue)
{
...
}
and your code will work fine.
Suggestion: Car and Bicycle shares properties, and the ICarbonFootprint implementation, so you can create a base class with an abstract method. Also the GetCarbonFootprint from ICarbonFootprint interface must be type of System.Double.
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
public class Building : ICarbonFootprint
{
public int BuildingSquareFootage { get; set; }
public string Address { get; set; }
public Building(int buildingSquareFootage, string address)
{
BuildingSquareFootage = buildingSquareFootage;
Address = address;
}
public int GetCarbonFootprint()
{
return BuildingSquareFootage * 50;
}
public override string ToString()
{
return string.Format("Building");
}
}
public abstract class CarBicycleBase : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
protected CarBicycleBase(string make, string model)
{
Make = make;
Model = model;
}
public abstract int GetCarbonFootprint();
}
public class Bicycle : CarBicycleBase
{
public Bicycle(string make, string model)
: base(make, model) { }
public override int GetCarbonFootprint()
{
return 0;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Car : CarBicycleBase
{
public int GallonOfGas { get; set; }
public Car(int gallonOfGas, string make, string model)
: base(make, model)
{
GallonOfGas = gallonOfGas;
}
public override int GetCarbonFootprint()
{
return GallonOfGas * 20;
}
public override string ToString()
{
return string.Format("Car");
}
}
Example:
...
var list = new List<ICarbonFootprint>(3)
{
new Car(10, "...", "..."),
new Bicycle("...", "..."),
new Building(20, "...")
};
foreach (ICarbonFootprint item in list)
item.GetCarbonFootprint();
...
I hope it helps.

Detecting changes within serializable data classes in C#

I've been experimenting with detecting changes in plain objects in C#. The aim being to have a container-type class for a bunch of data objects that can react when any one of them changes. For fun I wanted to see if all the work could be done in the container class, rather than resort to properties and dirty flags or events on the objects themselves.
What I'm curious about is whether there is a smart, fast and efficient way of doing this. My attempt is below, and it's none of those (the 'CheckStates' method would need to be called every frame for a start!) I've restricted it to only allow one instance per type, which suits my needs.
Note that an object passed in might be as follows:
[Serializable]
public class PlayerInfo
{
public string name = string.Empty;
public int score = 0;
}
Then the container:
public class AppState
{
private class StateData
{
public System.Object instance = null;
public Byte[] currentState = new Byte[0];
public Byte[] previousState = new Byte[0];
}
private Dictionary<Type, StateData> _allStates = new Dictionary<Type, StateData>();
private BinaryFormatter _formatter = new BinaryFormatter();
private MemoryStream _memoryStream = new MemoryStream();
public T GetState<T>() where T : class, new()
{
T state = default(T);
var stateType = typeof(T);
StateData stateData;
if(_allStates.TryGetValue(stateType, out stateData))
{
state = ReadData<T>(stateData);
}
else
{
var newState = CreateData<T>(out state);
_allStates[stateType] = newState;
}
return state;
}
public void CheckStates()
{
foreach(var state in _allStates)
{
if(HasChanged(state.Value))
{
Console.WriteLine(state.Key.ToString() + " has changed");
UpdateState(state.Value);
}
}
}
private StateData CreateData<T>(out T instance) where T : class, new()
{
instance = new T();
var stateData = new StateData();
stateData.instance = instance;
_formatter.Serialize(_memoryStream, instance);
var bytes = _memoryStream.ToArray();
stateData.currentState = bytes;
stateData.previousState = bytes;
return stateData;
}
private T ReadData<T>(StateData data) where T : class, new()
{
return data.currentState as T;
}
private bool HasChanged(StateData data)
{
_memoryStream.Position = 0;
_formatter.Serialize(_memoryStream, data.instance);
var current = _memoryStream.ToArray();
var previous = data.previousState;
if(current.Length != previous.Length)
{
return true;
}
for(int i = 0; i < current.Length; ++i)
{
if(current[i] != previous[i])
{
return true;
}
}
return false;
}
private void UpdateState(StateData data)
{
_memoryStream.Position = 0;
_formatter.Serialize(_memoryStream, data.instance);
data.previousState = _memoryStream.ToArray();
}
}
Alternatives I could think of were:
use structs instead of serializable classes (being forced to pass by value would mean that any change would have to go through a 'set' method on the container)
have the AppState's 'GetState' method return an IDisposable wrapper, which on Dispose could trigger a check for changes on that type (only problem is that there's nothing to stop someone from storing a reference to the object and modifying it without the container knowing)
EDIT: should add that it doesn't need to be thread-safe
I don't regard serializable classes as POCO, because you're engineering the classes so that they work with your change detection mechanism. So I wouldn't call them plain.
Your alternatives:
use structs instead of serializable classes
Don't use mutable structs Why are mutable structs “evil”?. And if your struct is immutable, then you might as well pass by reference, i.e. have a class.
have the 'get' method return an IDisposable wrapper
I'm not sure what get method you are referring to.
Proxy
One alternative is to allow a descendant proxy to react to calls to the setters:
public class PlayerInfo
{
public virtual string Name { get; set; }
public virtual int Score { get; set; }
}
public class PlayerInfoDetection : PlayerInfo
{
public int Revision { get; private set; }
public override string Name
{
set
{
base.Name = value;
Revision++;
}
}
public override int Score
{
set
{
base.Score = value;
Revision++;
}
}
}
private static void Example()
{
PlayerInfo pi = new PlayerInfoDetection();
Console.WriteLine(((PlayerInfoDetection)pi).Revision);
pi.Name = "weston";
Console.WriteLine(((PlayerInfoDetection)pi).Revision);
pi.Score = 123;
Console.WriteLine(((PlayerInfoDetection)pi).Revision);
}
This is how NHibernate "watches" objects fetched from the database, and why every object property must be virtual in NHibernate.
Aspect orientated
The same could be achieved with a product like post sharp where you could annotate your class to tell it when the revision must be changed.
public class PlayerInfo
{
public int Revision { get; private set; }
public string Name { get; [IncreaseRevision] set; }
public int Score { get; [IncreaseRevision] set; }
}
Making use of a well implemented hash function
Hash functions should not change their value while the object is in a container such as a hash set. We can make use of this to detect changes.
Drawback Note that any Hash collisions will yield incorrect results. This includes duplicates.
[TestClass]
public class ChangeDetectUnitTest
{
public class ChangeDetectList<T>
{
private readonly List<T> list = new List<T>();
private readonly ISet<T> hashes = new HashSet<T>();
public bool HasChanged(T t)
{
return !hashes.Contains(t);
}
public void Add(T t)
{
list.Add(t);
hashes.Add(t);
}
public void Reset()
{
hashes.Clear();
foreach (var t in list)
hashes.Add(t);
}
}
public class PlayerInfo
{
public string Name { get; set; }
public int Score { get; set; }
public override int GetHashCode()
{
//every field that you want to detect must feature in the hashcode
return (Name ?? "").GetHashCode() * 31 + Score;
}
public override bool Equals(object obj)
{
return Equals(obj as PlayerInfo);
}
public bool Equals(PlayerInfo other)
{
if (other == null) return false;
return Equals(other.Name, Name) && Score == Score;
}
}
private ChangeDetectList<PlayerInfo> list;
[TestInitialize]
public void Setup()
{
list = new ChangeDetectList<PlayerInfo>();
}
[TestMethod]
public void Can_add()
{
var p1 = new PlayerInfo();
list.Add(p1);
Assert.IsFalse(list.HasChanged(p1));
}
[TestMethod]
public void Can_detect_change()
{
var p1 = new PlayerInfo();
list.Add(p1);
p1.Name = "weston";
Assert.IsTrue(list.HasChanged(p1));
}
[TestMethod]
public void Can_reset_change()
{
var p1 = new PlayerInfo();
list.Add(p1);
p1.Name = "weston";
list.Reset();
Assert.IsFalse(list.HasChanged(p1));
}
}

C# - Event Design considerations

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.

Categories