Check if instance of class exists with certain property - c#

I have a list of classes, each with four properties:
public class BroncoClass
{
public NPC npc { get; set; }
public int TimeLeft { get; set; }
public bool Gravity { get; set; }
public bool Rotation { get; set; }
}
public List<BroncoClass> BroncoList = new List<BroncoClass>();
I want to check if the list contains a class with a specific npc value, for example:
for (int i = 0; i < Main.npc.Length; i++) // For every alive npc
{
if(BroncoList.contains a class where npc == Main.npc[i])
{
}
}
Haven't been able to find an answer online, any help is appreciated.

The real solution is to just keep a collection somewhere and use LINQ to query it. Presumably this collection would be easy to maintain as it would be the collection that is used for all other operations with BroncoClass.
After update to OP...
You already have the list, just use list.Any(o => o.npc == testNpc) or whatever other predicate you may need.
However, if you really want to do the actual question:
Sounds like a reasonable usage of a factory pattern; but you will need to effectively do manual memory management. Your factory would be something like:
// Could be static, but I hate static. Don't use static.
public class BroncoFactory
{
private List<BroncoClass> trackedObjects = new List<BroncoClass>();
public BroncoClass New()
{
var newInstance = new BroncoClass();
trackedObjects.Add(newInstance)
}
// Don't forget to call this or you'll leak!
public void Free(BroncoClass instance)
{
trackedObjects.Remove(instance);
}
public bool ExistsWithNPC(NPC test)
{
return trackedObjects.Any(o => o.npc == test);
}
}
Just really, really don't forget to call Free on an object when you are done with it.

Very similar to #BradleyDotNET's answer. I just folded the factory into the class as static methods. I'm not saying this is right way to go, I'm just offering it as a solution to your question. Using static methods in the class seems closer to what the OP is asking about.
First, I needed an NPC class to get this to compile. Notice that it implements IEquatable so that I can compare instances for equality the way I want to (and that I override GetHashCode because that's a requirement).
public class NPC : IEquatable<NPC>
{
private static int _indexKeeper = 0;
public int Index { get; } = _indexKeeper++;
public bool Equals(NPC other)
{
return Index == other?.Index;
}
public override int GetHashCode()
{
return Index.GetHashCode();
}
}
With that, here's the BroncoClass (mostly untested):
public class BroncoClass
{
private BroncoClass(int timeLeft, bool gravity, bool rotation)
{
Npc = new NPC();
TimeLeft = timeLeft;
Gravity = gravity;
Rotation = rotation;
}
public NPC Npc { get; set; }
public int TimeLeft { get; set; }
public bool Gravity { get; set; }
public bool Rotation { get; set; }
private static List<BroncoClass> _instances = new List<BroncoClass>();
public static BroncoClass Create(int timeLeft, bool gravity, bool rotation)
{
var bronco = new BroncoClass(timeLeft, gravity, rotation);
_instances.Add(bronco);
return bronco;
}
public static bool Remove(NPC npc)
{
var broncoFound = _instances.FirstOrDefault(b => b.Npc == npc);
if (broncoFound == null)
{
return false;
}
_instances.Remove(broncoFound);
return true;
}
public static BroncoClass Find(NPC npc)
{
return _instances.FirstOrDefault(b => b.Npc == npc);
}
}

Related

Performing calculations on properties generically and fast

The goal is to create a method which generically performs calculations on a property of a list of objects in a performant manner. Below is the entire test code:
using System;
using System.Collections.Generic;
namespace TestApp
{
public class Minute
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
public float Mult2 { get; set; }
public float Mult3 { get; set; }
public float Mult4 { get; set; }
}
class Program
{
public static List<Minute> Minutes = new List<Minute>();
static void Main(string[] args)
{
for (int i = 1; i < 10000000; i++)
{
Minute newMinute = new Minute();
newMinute.Source = i;
Minutes.Add(newMinute);
}
GenerateMult2(Minutes, 2); // 160 ms
GenerateMult2Generic(Minutes, typeof(Minute), nameof(Minute.Source), nameof(Minute.Mult2),2); // 4300 ms
}
public static void GenerateMult2(List<Minute> Minutes, int multiplier)
{
for (int i = 0; i < Minutes.Count; i++)
{
// Simplified calculation, there will eventually be a lot more code that goes here!
Minutes[i].Mult2 = Minutes[i].Source * multiplier;
}
}
public static void GenerateMult2Generic<T>(List<T> SourceList, Type ContainerType, string propNameSource, string propNameMult, int multiplier)
{
var propertyInfoSource = ContainerType.GetProperty(propNameSource);
var propertyInfoMult = ContainerType.GetProperty(propNameMult);
foreach (T item in SourceList)
{
float sourceValue = (float)propertyInfoSource.GetValue(item);
propertyInfoMult.SetValue(item, sourceValue * multiplier);
}
}
}
}
In this test app there is a method called GenerateMult2, whose purpose is to make some calculation on one of the properties in a list of Minute objects. This method works fine and is fast. The problem is that the method is too specific. If I wanted to do the same calculations on the properties Mult3 and Mult4, I would need to make a separate method for each of these properties, which is too much duplicated code. I want to make this method more generic, which is, I want the method to accept lists of other types as well, for example a list of Day objects or Second objects. Furthermore, I want to tell the method which property to perform the calculations on.
So I've made an attempt at creating a generic method called GenerateMult2Generic. This method performs the exact same calculation as the GenerateMult2 method, and is multipurpose, which is what I want. The huge disadvantage is that it's way too slow due to the reflections.
How can the GenerateMult2 method be made in a generic fashion, but with a performance penalty of no more than 5%?
Update with solution
Having studied the answers here, the best is one that was given by Ed Plunkett, but somehow was removed. Therefore, I'm posting the original code updated with the ideas from that answer:
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestApp
{
public class Minute : BaseTime
{
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class Day : BaseTime
{
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class BaseTime
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
}
class Program
{
public static List<Minute> Minutes = new List<Minute>();
public static List<Day> Days = new List<Day>();
static void Main(string[] args)
{
Minutes = Enumerable.Range(1, 10000000).Select(n => new Minute { Source = n }).ToList();
Days = Enumerable.Range(1, 10000000).Select(n => new Day { Source = n }).ToList();
// Generating data for Minutes
GenerateMovingAverage(Minutes, 100, (m, value) => ((Minute)m).MovingAverageFast = value);
GenerateMovingAverage(Minutes, 500, (m, value) => ((Minute)m).MovingAverageSlow = value);
GenerateRsi(Minutes, 60, (m, value) => ((Minute)m).RsiFast = value);
GenerateRsi(Minutes, 250, (m, value) => ((Minute)m).RsiSlow = value);
// Generating data for Days
GenerateMovingAverage(Days, 8, (d, value) => ((Day)d).MovingAverageFast = value);
GenerateMovingAverage(Days, 45, (d, value) => ((Day)d).MovingAverageSlow = value);
GenerateRsi(Days, 5, (d, value) => ((Day)d).RsiFast = value);
GenerateRsi(Days, 21, (d, value) => ((Day)d).RsiSlow = value);
}
public static void GenerateMovingAverage(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
float newValue;
newValue = BaseTimeObject.Source * Period; // pseudo calculation for generating moving average
setter(BaseTimeObject, newValue);
}
}
public static void GenerateRsi(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
float newValue;
newValue = BaseTimeObject.Source / Period; // pseudo calculation for generating rsi
setter(BaseTimeObject, newValue);
}
}
}
}
The key idea here is setting the property via an Action in the caller. With this solution, the calculation methods are reused for any object and any property with good performance.
In addition to what #iSR5 wrote, you might consider using a factory design pattern, making classes that do the actual calculations. This would be good if you don't know what you actually need to do until run time.
public interface IMultiValueGenerator
{
void GenerateValue(ITimeMulti multi, int multiplier);
}
public class Multi2Generator : IMultiValueGenerator
{
public void GenerateValue(ITimeMulti multi, int multiplier)
{
multi.Mult2 = multi.Source * multiplier;
}
}
public static class MultiGeneratorFactory
{
public static IMultiValueGenerator GetGenerator(...)
{
if (condition)
return new Multi2Generator();
// etc
}
}
Not sure if I've got the full picture here, but from my understanding, you'll need to have an interface with a base class. The interface is the one that you'll use to define the object, while the base class is the container for all common operations, which can be inhered by the class children. Then, you can create child class (as many as you want) and inherit the base class. The child class will have its required properties, methods, and logic if needed.
Enough talking, let's take it in code :
interface ITimeMulti
{
DateTime DateTimeUtc { get; set; }
float Source { get; set; }
// will be used for number of available properties.
int MultCount { get; }
// the main method for generating the multipliers.
void Generate(int multNumber, int multiplier);
}
Simple ? let's now create the base class :
public class TimeMulti : ITimeMulti
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
// Using Dictionary will be much faster than Reflection
protected static Dictionary<string, float> Multipliers { get; set; }
// Number of Properties (the set should be within the derived classes)
public int MultCount { get; protected set; }
// This is a restriction to create this instance from the derived classes only
private TimeMulti() { }
// for derived classes
protected TimeMulti(int multCount)
{
// Should be in this constructor only
Initiate(multCount);
}
// This is the main method to generate the multiplication part.
public void Generate(int multNumber, int multiplier)
{
if (multNumber == 0)
{
Multipliers["Mult"] = Source * multiplier;
}
else if (Multipliers.ContainsKey("Mult" + multNumber))
{
// store the value in the dictionary (this is for reference)
Multipliers["Mult" + multNumber] = SetMult(multNumber, Source * multiplier);
}
else
{
throw new NullReferenceException();
}
}
// On new instance, this will fired, which will setup the dictionary
protected void Initiate(int numberOfMultipliers)
{
// Ensure you have an active instance of the dictionary
if (Multipliers == null)
Multipliers = new Dictionary<string, float>();
// Ensurance
if(numberOfMultipliers > 0)
{
MultCount = numberOfMultipliers;
for (int x = 1; x <= numberOfMultipliers; x++)
if (!Multipliers.ContainsKey("Mult" + x))
Multipliers.Add("Mult" + x, 0);
}
else
{
throw new ArgumentOutOfRangeException();
}
}
// this is where we will replace Reflection, here is just returning the multValue
// we will override it on the derived classes
protected virtual float SetMult(int MultNumber, float multValue) => multValue;
}
Now, the derived class
public class Minute : TimeMulti
{
public float Mult1 { get; set; }
public float Mult2 { get; set; }
public float Mult3 { get; set; }
public float Mult4 { get; set; }
// MultCount = 4
public Minute(): base(4) { }
// This method will set the value of the property using switch statment, with this, you will avoid Reflection.
protected override float SetMult(int multNumber, float multValue)
{
switch (multNumber)
{
case 1:
Mult1 = multValue;
break;
case 2:
Mult2 = multValue;
break;
case 3:
Mult3 = multValue;
break;
case 4:
Mult4 = multValue;
break;
}
return multValue;
}
}
Now, you can do this :
class Program
{
// Create List with type of the ITimeMulti interface
public static List<ITimeMulti> Minutes = new List<ITimeMulti>();
static void Main(string[] args)
{
// Generate a sample
for (int i = 1; i < 10000000; i++)
Minutes.Add(new Minute() { Source = i});
// Calculate
GenerateMultipliers(Minutes, 1, 2);
}
public static void GenerateMultipliers(List<ITimeMulti> source, int multNumber, int multiplier)
{
for (int i = 0; i < source.Count; i++)
{
source[i].Generate(multNumber, multiplier);
}
}
}
If you want to create a new derived class :
public class Day : TimeMulti
{
// Properties
public float Mult1 { get; set; }
// Constructor
public Day(): base(1) { }
// This method to map the values to the properties
protected override float SetMult(int multNumber, float multValue)
{
switch (multNumber)
{
case 1:
Mult1 = multValue;
break;
}
return multValue;
}
}
This is just an example to give you a new ideas, you can do your own magic. I wouldn't go with Mult1 ...etc. I would go with a unique and a descriptive names.
Updated :
You can improve the performance of your updated code, by gathering all common properties in the base and make use of virtual and override if you want to have something override-able in a child class. Or, use interface and struct instead of classes. Also, instead of using IEnumerable use Array this would improve your performance as well.
public class BaseTime
{
// shared proprties
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class Minute : BaseTime
{
// add your custom code for Minute
// No need for recreating them, since it's already inherited from the base
}
public class Day : BaseTime
{
// add your custom code for Day
// No need for recreating them, since it's already inherited from the base
}
class Program
{
public static BaseTime[] Minutes;
public static BaseTime[] Days;
static void Main(string[] args)
{
Minutes = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Minute { Source = n }).ToArray();
Days = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Day { Source = n }).ToArray();
// Generating data for Minutes
GenerateMovingAverage(Minutes, 100, (m, value) => m.MovingAverageFast = value);
GenerateRsi(Minutes, 60, (m, value) => m.RsiFast = value);
GenerateRsi(Minutes, 250, (m, value) => m.RsiSlow = value);
// Generating data for Days
GenerateMovingAverage(Days, 8, (d, value) => d.MovingAverageFast = value);
GenerateMovingAverage(Days, 45, (d, value) => d.MovingAverageSlow = value);
GenerateRsi(Days, 5, (d, value) => d.RsiFast = value);
GenerateRsi(Days, 21, (d, value) => d.RsiSlow = value);
}
public static void GenerateMovingAverage(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
setter(BaseTimeObject, BaseTimeObject.Source * Period);
}
}
public static void GenerateRsi(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
setter(BaseTimeObject, BaseTimeObject.Source / Period);
}
}
}

Generic class<T> with constructor to choose the type

I have three classes that have all the same named Properties. Let's say the classes are Sword, Bow and Hammer -- and the properties are Damage and Range. How could I instantiate a class of Weapon<T> with a constructor where I pass an int to choose the Type of this class?
I am not sure if this is even the right way to do what I want to.
public class Weapon<T>
{
}
public class Sword
{
public int Damage { get => 10; }
public int Range { get => 12; }
}
public class Bow
{
public int Damage { get => 8; }
public int Range { get => 28; }
}
public class Hammer
{
public int Damage { get => 15; }
public int Range { get => 8; }
}
What you´ve described is known as factory-pattern. You have some factory that is able to instantiate other objects, in your case depending on an integer:
class WeaponFactory
{
public static IWeapon CreateWeapon(WeaponType type)
{
switch type:
case WeaponType.Sword: return new Sword();
case WeaponType.Hammer: return new Hammer();
case WeaponType.Bow: return new Bow();
default: throw new ArgumentException("Unknown weaponType");
}
}
enum WeaponType { Sword, Hammer, Bow }
interface IWeapon
{
int Damage { get; }
int Range { get; }
}
Finally all your classes should implement that interface. Now you can easily create instances with the following code:
var hammer = WeaponFactory.CreateWeapon(WeaponType.Hammer);
I'd simplify this beyond what you have and also beyond the other solutions proposed.
public class Weapon
{
private int _range;
private int _damage;
public Weapon(int range, int damage)
{
_range = range;
_damage = damage;
}
public int Range => _range;
public int Damage => _damage;
}
There's no real need for polymorphism here - all you want to do is assign different readonly values at runtime. If you later want differing behaviour per weapon, you can achieve that with the strategy pattern.
I'd then just use factories to instantiate different weapons.
What those factories looked like would depend on how they need to be called but in practice your factory method could look something like this:
public Weapon GetWeapon(string weaponType)
{
var weaponProperties = propertiesFor(weaponType);
return new Weapon(weaponProperties.Range, weaponProperties.Damage);
}
Where propertiesFor looks up the appropriate values for the given weapon type in a dictionary, file etc. etc.
I would steer clear of an IWeapon interface unless you really need to supply different implementations of weapons at runtime. Don't write it 'til you need it. Declaring an interface just for the purposes of mocking in tests (as some others have suggested) would normally indicate to me that your test boundaries are off or you have some dependencies to isolate better (but that's a broader conversation).
public interface IWeapon
{
int Damage { get; }
int Range { get; }
}
public class Weapon : IWeapon
{
protected int _damage, _range;
public int Damage
{
get { return _damage; }
}
public int Range
{
get { return _range; }
}
}
public class Sword : Weapon
{
public Sword()
{
_damage = 10;
_range = 12;
}
}
public class Bow : Weapon
{
public Bow()
{
_damage = 8;
_range = 28;
}
}
public class Hammer : Weapon
{
public Hammer()
{
_damage = 15;
_range = 8;
}
}
Inherit from a base class
public class Weapon
{
public int Damage { get; set; }
public int Range { get; set; }
}
public class Sword : Weapon
{
}
public class Bow : Weapon
{
}
public class Hammer : Weapon
{
}
and instanciate this way
Weapon item = new Sword() { Damage = 10, Range = 20 };
You could start by creating interface for parent weapon class. Then extend weapon class with child classes to make swords, hammers and etc... Then you can add custom properties for each child class and still use them as weapon because they all share same interface/parent class and they all have attack method...
public interface IWeapon
{
int Damage { get; }
int Range { get; }
void Attack();
}
public class Weapon : IWeapon
{
public int Damage { get; private set; }
public int Range { get; private set; }
public Weapon(int damage, int range)
{
Damage = damage;
Range = range;
}
public virtual void Attack()
{
Console.WriteLine("Weapon: Attack");
}
}
public class Sword : Weapon
{
//some sword properties here...
public Sword(int damage, int range) : base(damage, range)
{
}
public override void Attack()
{
Console.WriteLine("Weapon Sword: Attack");
}
}
public class Bow : Weapon
{
//some bow properties here...
public Bow(int damage, int range) : base(damage, range)
{
}
public override void Attack()
{
Console.WriteLine("Weapon Bow: Attack");
}
}
public class Hammer : Weapon
{
//some hammer properties here...
public Hammer(int damage, int range) : base(damage, range)
{
}
public override void Attack()
{
Console.WriteLine("Weapon Hammer: Attack");
}
}
class Program
{
public static void Main(string[] args)
{
IWeapon hammerWeapon = new Hammer(15, 10);
hammerWeapon.Attack();
}
}

Bidirectional connected between to C# classes

I'm currently working on project (for fun) that involves simulating logic gates. I have a Connection.cs and a Gate.cs that is the parent of other classes like Not, And, Or, etc. In my Gate class I have an abstract method Evaluate that will end up doing the work with inputs and setting outputs.
public abstract class Gate : IConnectable {
private int[] inputs;
private int[] outputs;
protected Gate(int inputCount, int outputCount) {
inputs = new int[inputCount];
outputs = new int[outputCount];
}
...
public abstract void Evaluate();
}
public class Connection {
private IConnectable input;
private IConnectable output;
public Connection(IConnectable from, IConnectable to) {
input = from;
output = to;
}
}
In the end, I am trying to figure out a concise way to have a Gate object contain references to its connections that are inputs/outputs and to have the Connections know what is on either end of the "wire". Is there an easy way to do this?
Generally you want some way to represent a graph. There are many ways to do that.
I would consider a design like this as a starting point:
interface IGate
{
bool Value { get; }
}
class And : IGate
{
public IGate X { get; private set; }
public IGate Y { get; private set; }
public bool Value
{
get
{
return X.Value && Y.Value;
}
}
public And(IGate x, IGate y)
{
X = x;
Y = y;
}
}
class Input : IGate
{
public bool Value { get; set; }
public Input(bool value)
{
Value = value;
}
}
An example is:
new And(new Input(true), new And(new Input(true), new Input(false))).Value
I usually do something like this
public class Node {
private static List<Node> nodes = new List<Node>();
private List<Node> inputs { get; set;}
private List<Node> outputs {get;set;}
protected Node() { }
protected Node(Node input, Node outPut) {
Node newNode = new Node();
nodes.Add(newNode);
newNode.inputs.Add(input);
newNode.outputs.Add(output);
}
}

Auto-properties with mutable objects

I'm trying to make properties for mutable objects. Is this a problem with Auto-properties? For example, the following code would allow for unwanted manipulation of the mutable object. How would I avoid this?
public class Mutable{
public int Value { get; set; }
}
public class ClassWithMutable{
public Mutable Object { get; }
public ClassWithMutable(){
this.mutable = new Mutable();
this.mutable.Value = 0;
}
}
public class Demo{
public static void Main(String[] args){
ClassWithMutable test = new ClassWithMutable();
Mutable o = test.Object;
o.Value = 1;
}
}
You could use an interface that only exposes the get of the properties, and a private class that implements it.
public interface IImmutable {
int Value { get; }
}
public class ClassWithImmutable{
private Mutable _object;
public IImmutable Object { get { return _object; } }
public ClassWithImmutable(){
this._object = new Mutable();
this._object.Value = 0;
}
private class Mutable : IImmutable {
public int Value { get; set; }
}
}
public class Demo{
public static void Main(String[] args){
ClassWithImmutable test = new ClassWithImmutable();
IImmutable o = test.Object;
o.Value = 1; // fails
}
}
I'm trying to understand the intent of your question rather than your question, and I'm coming up a little short. However, I think I came up with something.
You can "mask" your mutable object under a read-only interface.
public class ClassWithMutable
{
public IImumutable Mutable { get { return _mutable; } }
private Mutable _mutable;
public ClassWithMutable()
{
_mutable = new Mutable()
{
Value = 1
};
}
}
public interface IImumutable
{
int Value { get; }
}
public class Mutable : IImumutable
{
public int Value { get; set; }
}
As long as your ClassWithMutable instance exposes the Mutable instance as an Immutable then the consumer can't easily change it. (I emphasize easily, because there's pretty much always a way that you can change it. It just depends on how hard you want to work.)

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));
}
}

Categories