I have problems wit hthe implementation of a generic sorting algorithm.
We need to implement quicksort and selection sort, and a class which should be sortable using these functions. The functions should be generic, and thus work on other classes as well.
I tested the quicksort. It works perfectly on a List. However, when trying to execute it on my own comparable class, it says:
There is no implicit reference conversion from 'SNIP' to 'System.IComparable'
Do you guys have any idea what the problem can be?
Here is my comparable class:
public class SNIP : IComparable
{
private long lCost { get; set; }
public SNIP(long lCost)
{
this.lCost = lCost;
}
public int CompareTo(object obj)
{
if (obj == null) return 1;
SNIP oOtherPlank = obj as SNIP;
if (oOtherPlank != null)
return this.lCost.CompareTo(oOtherPlank.lCost);
else
throw new ArgumentException("Can only compare SNIPs.");
}
}
Thanks in advance!
Thanks to #Sweeper, the comparable is now fixed.
Like he said, I had to define my class better:
public class SNIP : IComparable<SNIP>
{
private long lCost { get; set; }
public SNIP(long lCost)
{
this.lCost = lCost;
}
public int CompareTo(SNIP obj)
{
if (obj == null) return 1;
SNIP oOtherSnip= obj as SNIP;
if (oOtherSnip!= null)
return this.lCost.CompareTo(oOtherSnip.lCost);
else
throw new ArgumentException("Can only compare SNIPs.");
}
}
It is also important to note that this only works when the argument of the CompareTo method is actually of the right class. I tried defining the class as IComparable before, but it didn't work because the argument in CompareTo was set to an object. By changing both the CompareTo header and the class header, the problem is fixed and the sorting now works.
Thanks a lot :-)
You can implement generic IComparable<SNIP>, not IComparable which is very simple: this is always geater than null and if we compare with not null other we should check lCost.
public class SNIP : IComparable<SNIP>
{
private long lCost { get; set; }
public SNIP(long lCost)
{
this.lCost = lCost;
}
public int CompareTo(SNIP other) => other is null
? 1
: lCost.CompareTo(other.lCost);
}
then you can sort: note that since List<SNIP> is generic, the generic IComparable<SNIP> will be used on sorting.
List<SNIP> list = new List<SNIP>()
{
new SNIP(5),
new SNIP(1),
new SNIP(3),
};
list.Sort();
I have a class that is IComparable:
public class a : IComparable
{
public int Id { get; set; }
public string Name { get; set; }
public a(int id)
{
this.Id = id;
}
public int CompareTo(object obj)
{
return this.Id.CompareTo(((a)obj).Id);
}
}
When I add a list of object of this class to a hash set:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(a1);
Everything is fine and ha.count is 2, but:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(new a(1));
Now ha.count is 3.
Why doesn't HashSet respect a's CompareTo method.
Is HashSet the best way to have a list of unique objects?
It uses an IEqualityComparer<T> (EqualityComparer<T>.Default unless you specify a different one on construction).
When you add an element to the set, it will find the hash code using IEqualityComparer<T>.GetHashCode, and store both the hash code and the element (after checking whether the element is already in the set, of course).
To look an element up, it will first use the IEqualityComparer<T>.GetHashCode to find the hash code, then for all elements with the same hash code, it will use IEqualityComparer<T>.Equals to compare for actual equality.
That means you have two options:
Pass a custom IEqualityComparer<T> into the constructor. This is the best option if you can't modify the T itself, or if you want a non-default equality relation (e.g. "all users with a negative user ID are considered equal"). This is almost never implemented on the type itself (i.e. Foo doesn't implement IEqualityComparer<Foo>) but in a separate type which is only used for comparisons.
Implement equality in the type itself, by overriding GetHashCode and Equals(object). Ideally, implement IEquatable<T> in the type as well, particularly if it's a value type. These methods will be called by the default equality comparer.
Note how none of this is in terms of an ordered comparison - which makes sense, as there are certainly situations where you can easily specify equality but not a total ordering. This is all the same as Dictionary<TKey, TValue>, basically.
If you want a set which uses ordering instead of just equality comparisons, you should use SortedSet<T> from .NET 4 - which allows you to specify an IComparer<T> instead of an IEqualityComparer<T>. This will use IComparer<T>.Compare - which will delegate to IComparable<T>.CompareTo or IComparable.CompareTo if you're using Comparer<T>.Default.
Here's clarification on a part of the answer that's been left unsaid: The object type of your HashSet<T> doesn't have to implement IEqualityComparer<T> but instead just has to override Object.GetHashCode() and Object.Equals(Object obj).
Instead of this:
public class a : IEqualityComparer<a>
{
public int GetHashCode(a obj) { /* Implementation */ }
public bool Equals(a obj1, a obj2) { /* Implementation */ }
}
You do this:
public class a
{
public override int GetHashCode() { /* Implementation */ }
public override bool Equals(object obj) { /* Implementation */ }
}
It is subtle, but this tripped me up for the better part of a day trying to get HashSet to function the way it is intended. And like others have said, HashSet<a> will end up calling a.GetHashCode() and a.Equals(obj) as necessary when working with the set.
HashSet uses Equals and GetHashCode().
CompareTo is for ordered sets.
If you want unique objects, but you don't care about their iteration order, HashSet<T> is typically the best choice.
constructor HashSet receive object what implement IEqualityComparer for adding new object.
if you whant use method in HashSet you nead overrride Equals, GetHashCode
namespace HashSet
{
public class Employe
{
public Employe() {
}
public string Name { get; set; }
public override string ToString() {
return Name;
}
public override bool Equals(object obj) {
return this.Name.Equals(((Employe)obj).Name);
}
public override int GetHashCode() {
return this.Name.GetHashCode();
}
}
class EmployeComparer : IEqualityComparer<Employe>
{
public bool Equals(Employe x, Employe y)
{
return x.Name.Trim().ToLower().Equals(y.Name.Trim().ToLower());
}
public int GetHashCode(Employe obj)
{
return obj.Name.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
HashSet<Employe> hashSet = new HashSet<Employe>(new EmployeComparer());
hashSet.Add(new Employe() { Name = "Nik" });
hashSet.Add(new Employe() { Name = "Rob" });
hashSet.Add(new Employe() { Name = "Joe" });
Display(hashSet);
hashSet.Add(new Employe() { Name = "Rob" });
Display(hashSet);
HashSet<Employe> hashSetB = new HashSet<Employe>(new EmployeComparer());
hashSetB.Add(new Employe() { Name = "Max" });
hashSetB.Add(new Employe() { Name = "Solomon" });
hashSetB.Add(new Employe() { Name = "Werter" });
hashSetB.Add(new Employe() { Name = "Rob" });
Display(hashSetB);
var union = hashSet.Union<Employe>(hashSetB).ToList();
Display(union);
var inter = hashSet.Intersect<Employe>(hashSetB).ToList();
Display(inter);
var except = hashSet.Except<Employe>(hashSetB).ToList();
Display(except);
Console.ReadKey();
}
static void Display(HashSet<Employe> hashSet)
{
if (hashSet.Count == 0)
{
Console.Write("Collection is Empty");
return;
}
foreach (var item in hashSet)
{
Console.Write("{0}, ", item);
}
Console.Write("\n");
}
static void Display(List<Employe> list)
{
if (list.Count == 0)
{
Console.WriteLine("Collection is Empty");
return;
}
foreach (var item in list)
{
Console.Write("{0}, ", item);
}
Console.Write("\n");
}
}
}
I came here looking for answers, but found that all the answers had too much info or not enough, so here is my answer...
Since you've created a custom class you need to implement GetHashCode and Equals. In this example I will use a class Student instead of a because it's easier to follow and doesn't violate any naming conventions. Here is what the implementations look like:
public override bool Equals(object obj)
{
return obj is Student student && Id == student.Id;
}
public override int GetHashCode()
{
return HashCode.Combine(Id);
}
I stumbled across this article from Microsoft that gives an incredibly easy way to implement these if you're using Visual Studio. In case it's helpful to anyone else, here are complete steps for using a custom data type in a HashSet using Visual Studio:
Given a class Student with 2 simple properties and an initializer
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Student(int id)
{
this.Id = id;
}
}
To Implement IComparable, add : IComparable<Student> like so:
public class Student : IComparable<Student>
You will see a red squiggly appear with an error message saying your class doesn't implement IComparable. Click on suggestions or press Alt+Enter and use the suggestion to implement it.
You will see the method generated. You can then write your own implementation like below:
public int CompareTo(Student student)
{
return this.Id.CompareTo(student.Id);
}
In the above implementation only the Id property is compared, name is ignored. Next right-click in your code and select Quick actions and refactorings, then Generate Equals and GetHashCode
A window will pop up where you can select which properties to use for hashing and even implement IEquitable if you'd like:
Here is the generated code:
public class Student : IComparable<Student>, IEquatable<Student> {
...
public override bool Equals(object obj)
{
return Equals(obj as Student);
}
public bool Equals(Student other)
{
return other != null && Id == other.Id;
}
public override int GetHashCode()
{
return HashCode.Combine(Id);
}
}
Now if you try to add a duplicate item like shown below it will be skipped:
static void Main(string[] args)
{
Student s1 = new Student(1);
Student s2 = new Student(2);
HashSet<Student> hs = new HashSet<Student>();
hs.Add(s1);
hs.Add(s2);
hs.Add(new Student(1)); //will be skipped
hs.Add(new Student(3));
}
You can now use .Contains like so:
for (int i = 0; i <= 4; i++)
{
if (hs.Contains(new Student(i)))
{
Console.WriteLine($#"Set contains student with Id {i}");
}
else
{
Console.WriteLine($#"Set does NOT contain a student with Id {i}");
}
}
Output:
I tried to search for an answer for this problem but could not find much, most probably because I do not know how to look for it properly, so here it goes. All help is very much appreciated.
With the base class that looks like
abstract public class Property
{
private String name;
public Property(String propertyName)
{
name = propertyName;
}
public String Name
{
get { return name; }
}
abstract public override String ToString();
}
And derived classes that look like
public class StringProperty : Property
{
private String value; // different properties for different types
public StringProperty(String propertyName, String value) : base(propertyName)
{
this.value = value;
}
public String Value // different signature for different properties
{
get { return value; }
}
public override String ToString()
{
return base.Name + ": " + value;
}
}
During runtime, the function receives a collection of "Property" objects. What do I need to do to be able to obtain the "Value" of each? Do I need to have a big if statement to query the type of each "Property" object? If not, is there a more elegant solution?
I tried to define an abstract "Value" property to be overridden but since the return types are different, it did not work. I also tried playing with shadowing the "Value" property, but I could not make it work. The idea of using an COM-like Variant does not sound very appropriate, either.
Thanks a lot in advance.
EDIT:
I should have added details as to what I am trying to do. The properties are displayed in a Winforms app. Different "TextBox"es represent different properties and are filtered for proper input (depending on the type). The updated values are read back and stored. The container object will be serialized into JSON and deserialized on an Android and iPhone client and eventually these values will be passed into a layer running native C++ code doing OpenGL stuff. I don't know in advance the kind of all needed properties so as the middleman, I wanted to make my code as robust as possible while being able to feed the OpenGL engine.
You can use a generic class:
public class AnyProperty<T> : Property
{
private T value;
// ... etc
I'd really recommend making the base class an Interface by now:
public interface IProperty
{
public String Name { get; }
}
public class Property<T> : IProperty
{
public Property(String name, T value)
{
Name = name;
Value = value;
}
public String Name { get; private set; }
public T Value { get; private set; }
public override String ToString()
{
return string.Format("{0}: {1}", Name, Value)
}
}
Here is sample usage:
var intProp = new Property<int> ("age", 32);
var strProp = new Property<string> ("name", "Earl");
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);
To make the construction even simpler, you could have a factory method:
public static Property<T> MakeProperty(string name, T value)
{
return new Property<T>(name,value);
}
var intProp = MakeProperty("age", 32);
var strProp = MakeProperty("name", "Earl");
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);
Not necessarily recommended, and a bit OT:
You could make it even funkier with an extension method:
public static Property<T> AsProp<T>(this T value, string name)
{
return new Property<T>(name,value);
}
var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");
You would have to simply use the object type. What are you trying to accomplish? The problem here isn't the structure of your classes, it's the function that receives the collection of Property objects. It's impossible to even cast something to an unknown type, since you don't know what type of variable it needs to be stored in.
So basically, your Property.Value property needs to be of type object. In your method that uses the Property objects, you need to do something with them, and what you're doing will decide how it should be structured. Are you printing values out? Have a *Value class inheriting from an abstract PropertyValue class and override ToString() to return an appropriate string represention.
I made a few changes to your sample code and got this result...
abstract public class Property
{
private readonly String _name;
public Property(String propertyName)
{
_name = propertyName;
}
public String Name
{
get { return _name; }
}
abstract public override String ToString();
}
public class StringProperty : Property
{
private readonly dynamic _value; // different properties for different types
public StringProperty(String propertyName, dynamic value)
: base(propertyName)
{
this._value = value;
}
public dynamic Value // different signature for different properties
{
get { return _value; }
}
public override String ToString()
{
return base.Name + ": " + _value;
}
}
static void Main(string[] args)
{
StringProperty sp = new StringProperty("A double", 3.444);
StringProperty sp2 = new StringProperty("My int", 4343);
StringProperty sp3 = new StringProperty("My directory", new DirectoryInfo("Some directory"));
StringProperty sp4 = new StringProperty("My null", null);
Console.WriteLine(sp);
Console.WriteLine(sp2);
Console.WriteLine(sp3);
Console.WriteLine(sp4);
}
}
Values are properly printed to the console in the expected way.
It would require a bit of a rethink, but have you considered using the dynamic type (introduced in .net4)
Doesn't really solve your problem, but sidespteps it.
Your properties can bascically just be a
Dictionary<String, dynamic>
, the gotcha is they don't get evaluated until runtime, so you get no compiler support for typing.
so given you want
int SomeValue = MyProperties[SomePropertyName] + 10;
So if
MyProperties[SomePropertyName] = 10; // all is good
if its 76.52 or Fred, the addition will throw an exception at the point it executes.
Code is much simpler and cleaner, no extra casting and the amount of scaffolding required is minimal, BUT, you'll need to unit test code that uses the dictionary extensively and religiously.
I have a class which contains 5 properties.
If any value is assingned to any of these fields, an another value (for example IsDIrty) would change to true.
public class Class1
{
bool IsDIrty {get;set;}
string Prop1 {get;set;}
string Prop2 {get;set;}
string Prop3 {get;set;}
string Prop4 {get;set;}
string Prop5 {get;set;}
}
To do this you can't really use automatic getter & setters, and you need to set IsDirty in each setter.
I generally have a "setProperty" generic method that takes a ref parameter, the property name and the new value.
I call this in the setter, allows a single point where I can set isDirty and raise Change notification events e.g.
protected bool SetProperty<T>(string name, ref T oldValue, T newValue) where T : System.IComparable<T>
{
if (oldValue == null || oldValue.CompareTo(newValue) != 0)
{
oldValue = newValue;
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name));
isDirty = true;
return true;
}
return false;
}
// For nullable types
protected void SetProperty<T>(string name, ref Nullable<T> oldValue, Nullable<T> newValue) where T : struct, System.IComparable<T>
{
if (oldValue.HasValue != newValue.HasValue || (newValue.HasValue && oldValue.Value.CompareTo(newValue.Value) != 0))
{
oldValue = newValue;
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name));
}
}
You can implement the IChangeTracking or IRevertibleChangeTracking interfaces, now included in .NET Standard 2.0.
Implementation is as follows:
IChangeTracking:
class Entity : IChangeTracking
{
string _FirstName;
public string FirstName
{
get => _FirstName;
set
{
if (_FirstName != value)
{
_FirstName = value;
IsChanged = true;
}
}
}
string _LastName;
public string LastName
{
get => _LastName;
set
{
if (_LastName != value)
{
_LastName = value;
IsChanged = true;
}
}
}
public bool IsChanged { get; private set; }
public void AcceptChanges() => IsChanged = false;
}
IRevertibleChangeTracking:
class Entity : IRevertibleChangeTracking
{
Dictionary<string, object> _Values = new Dictionary<string, object>();
string _FirstName;
public string FirstName
{
get => _FirstName;
set
{
if (_FirstName != value)
{
if (!_Values.ContainsKey(nameof(FirstName)))
_Values[nameof(FirstName)] = _FirstName;
_FirstName = value;
IsChanged = true;
}
}
}
string _LastName;
public string LastName
{
get => _LastName;
set
{
if (_LastName != value)
{
if (!_Values.ContainsKey(nameof(LastName)))
_Values[nameof(LastName)] = _LastName;
_LastName = value;
IsChanged = true;
}
}
}
public bool IsChanged { get; private set; }
public void RejectChanges()
{
foreach (var property in _Values)
GetType().GetRuntimeProperty(property.Key).SetValue(this, property.Value);
AcceptChanges();
}
public void AcceptChanges()
{
_Values.Clear();
IsChanged = false;
}
}
Another option, which I like the most, is to use a change tracking library, such as TrackerDog, that generates all the boilerplate code for you, while just need to provide POCO entities.
There are more ways to achieve this if you don't want to implement all the properties by hand.
One option is to use a weaving library, such as Fody.PropertyChanged and Fody.PropertyChanging, and handle the change methods to cache old values and track object state.
Another option is to have the object's graph stored as MD5 or some other hash, and reset it upon any change, you might be surprised, but if you don't expect zillion changes and if you request it only on demand, it can work really fast.
Here is an example implementation (Note: requires Json.NET and Fody/PropertyChanged:
[AddINotifyPropertyChangedInterface]
class Entity : IChangeTracking
{
public string UserName { get; set; }
public string LastName { get; set; }
public bool IsChanged { get; private set; }
string hash;
string GetHash()
{
if (hash == null)
using (var md5 = MD5.Create())
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
{
_JsonSerializer.Serialize(writer, this);
var hash = md5.ComputeHash(stream);
this.hash = Convert.ToBase64String(hash);
}
return hash;
}
string acceptedHash;
public void AcceptChanges() => acceptedHash = GetHash();
static readonly JsonSerializer _JsonSerializer = CreateSerializer();
static JsonSerializer CreateSerializer()
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new EmptyStringConverter());
return serializer;
}
class EmptyStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
=> objectType == typeof(string);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
=> throw new NotSupportedException();
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
if (value is string str && str.All(char.IsWhiteSpace))
value = null;
writer.WriteValue(value);
}
public override bool CanRead => false;
}
}
Dan's solution is perfect.
Another option to consider if you're going to have to do this on multiple classes (or maybe you want an external class to "listen" for changes to the properties):
Implement the INotifyPropertyChanged interface in an abstract class
Move the IsDirty property to your abstract class
Have Class1 and all other classes that require this functionality to extend your abstract class
Have all your setters fire the PropertyChanged event implemented by your abstract class, passing in their name to the event
In your base class, listen for the PropertyChanged event and set IsDirty to true when it fires
It's a bit of work initially to create the abstract class, but it's a better model for watching for data changes as any other class can see when IsDirty (or any other property) changes.
My base class for this looks like the following:
public abstract class BaseModel : INotifyPropertyChanged
{
/// <summary>
/// Initializes a new instance of the BaseModel class.
/// </summary>
protected BaseModel()
{
}
/// <summary>
/// Fired when a property in this class changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Triggers the property changed event for a specific property.
/// </summary>
/// <param name="propertyName">The name of the property that has changed.</param>
public void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Any other model then just extends BaseModel, and calls NotifyPropertyChanged in each setter.
Set IsDirty to true in all of your setters.
You might also consider making the setter for IsDirty private (or protected, if you may have child classes with additional properties). Otherwise you could have code outside of the class negating its internal mechanism for determining dirtiness.
If there are a very large number of such classes, all having that same pattern, and you frequently have to update their definitions, consider using code generation to automatically spit out the C# source files for all the classes, so that you don't have to manually maintain them. The input to the code generator would just be a simple text file format that you can easily parse, stating the names and types of the properties needed in each class.
If there are just a small number of them, or the definitions change very infrequently during your development process, then it's unlikely to be worth the effort, in which case you may as well maintain them by hand.
Update:
This is probably way over the top for a simple example, but it was fun to figure out!
In Visual Studio 2008, if you add a file called CodeGen.tt to your project and then paste this stuff into it, you'll have the makings of a code generation system:
<## template debug="false" hostspecific="true" language="C#v3.5" #>
<## output extension=".cs" #>
<## assembly name="System.Core" #>
<## import namespace="System.Linq" #>
<#
// You "declare" your classes here, as in these examples:
var src = #"
Foo: string Prop1,
int Prop2;
Bar: string FirstName,
string LastName,
int Age;
";
// Parse the source text into a model of anonymous types
Func<string, bool> notBlank = str => str.Trim() != string.Empty;
var classes = src.Split(';').Where(notBlank).Select(c => c.Split(':'))
.Select(c => new
{
Name = c.First().Trim(),
Properties = c.Skip(1).First().Split(',').Select(p => p.Split(' ').Where(notBlank))
.Select(p => new { Type = p.First(), Name = p.Skip(1).First() })
});
#>
// Do not edit this file by hand! It is auto-generated.
namespace Generated
{
<# foreach (var cls in classes) {#> class <#= cls.Name #>
{
public bool IsDirty { get; private set; }
<# foreach (var prop in cls.Properties) { #>
private <#= prop.Type #> _storage<#= prop.Name #>;
public <#= prop.Type #> <#= prop.Name #>
{
get { return _storage<#= prop.Name #>; }
set
{
IsDirty = true;
_storage<#= prop.Name #> = value;
}
} <# } #>
}
<# } #>
}
There's a simple string literal called src in which you declare the classes you need, in a simple format:
Foo: string Prop1,
int Prop2;
Bar: string FirstName,
string LastName,
int Age;
So you can easily add hundreds of similar declarations. Whenever you save your changes, Visual Studio will execute the template and produce CodeGen.cs as output, which contains the C# source for the classes, complete with the IsDirty logic.
You can change the template of what is produced by altering the last section, where it loops through the model and produces the code. If you've used ASP.NET, it's similar to that, except generating C# source instead of HTML.
Both Dan's and Andy Shellam's answers are my favorites.
In anyway, if you wanted to keep TRACK of you changes, like in a log or so, you might consider the use of a Dictionary that would add all of your property changes when they are notified to have changed. So, you could add the change into your Dictionary with a unique key, and keep track of your changes. Then, if you wish to Roolback in-memory the state of your object, you could this way.
EDIT
Here's what Bart de Smet uses to keep track on property changes throughout LINQ to AD. Once the changes have been committed to AD, he clears the Dictionary. So, when a property changes, because he implemented the INotifyPropertyChanged interface, when a property actually changed, he uses a Dictionary> as follows:
/// <summary>
/// Update catalog; keeps track of update entity instances.
/// </summary>
private Dictionary<object, HashSet<string>> updates
= new Dictionary<object, HashSet<string>>();
public void UpdateNotification(object sender, PropertyChangedEventArgs e)
{
T source = (T)sender;
if (!updates.ContainsKey(source))
updates.Add(source, new HashSet<string>());
updates[source].Add(e.PropertyName);
}
So, I guess that if Bart de Smet did that, this is somehow a practice to consider.
There are multiple ways for change tracking with their pros and cons. Here are some ideas:
Observer Pattern
In .NET, the most common approach is to implement INotifyPropertyChanged, INotifyPropertyChangeing, and/or IObservable (see also Introduction to Rx). Tipp: The easiest way to do this is to use ReactiveObject from the ReactiveUI library as base object.
Using this interfaces, you can track when a property is changing or has changed. So this is the best method to react to changes in „real-time“.
You can also implement a change tracker to keep track of everything for more complex scenarios. The change tracker might have a list of the changes—listing property names, values, and timestamps as needed—internally. You can than query this list for the information you need. Think of something like the EventSourcing pattern.
Serialization and Diff
If you want to see if an object has changed and what has changed, you could serialize the original version and the current version.
One version of this is to serialize to JSON and calculate an JSON Patch. You can use the JsonPatchDocument<T> class (see also JsonPatchDocument Class) for this. The diff will tell you what has changed. (see also this question)
Manually
Then there is also the method of having multiple properties to keep the original state and the current state, and maybe an boolean that tells you if the field has changed but was changed back to the original value later.
This is very easy to implement, but might not be the best approach when handling more complex scenarios.
Carefully consider the underlying purpose the object tracking is required? Suppose if it is something like other objects have to do something based on another object's state, then consider implementing the observer design pattern.
If its something small consider implementing the INotifyPropertyChanged interface.
This is something that is built into the BusinessBase class in Rocky Lhokta's CLSA framework, so you could always go and look at how it's done...
I know this is an old thread, but I think Enumerations will not work with Binary Worrier's solution. You will get a design-time error message that the enum property Type "cannot be used as type parameter 'T' in the generic type or method"..."SetProperty(string, ref T, T)'. There is no boxing conversion...".
I referenced this stackoverflow post to solve the issue with enumerations: C# boxing enum error with generics
To support enums, please use the perfect solution of Binary Worrier and add the code below.
I have added Enum support for my own (and it was a pain), I guess this is nice to add as well.
protected void SetEnumProperty<TEnum>(string name, ref TEnum oldEnumValue, TEnum newEnumValue) where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!(typeof(TEnum).IsEnum)) {
throw new ArgumentException("TEnum must be an enumerated type");
}
if (oldEnumValue.CompareTo(newEnumValue) != 0) {
oldEnumValue = newEnumValue;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
_isChanged = true;
}
}
And implemented via:
Public Property CustomerTyper As CustomerTypeEnum
Get
Return _customerType
End Get
Set(value As ActivityActionByEnum)
SetEnumProperty("CustomerType", _customerType, value)
End Set
End Property
I know that it's been a while since you asked this. If you're still interested to keep your classes clean and simple without the need of deriving from base classes, I would suggest to use PropertyChanged.Fody that has an IsChanged Flag implemented
There actually is a way by checking the object fields.
I know this isn't the way that you wanted, you need an extra call to check it but you can use this Script:
using System.Reflection;
using System.Collections.Generic;
namespace Tracking
{
public static class Tracker
{
public static List<(string Key, (FieldInfo Info, object Value)[] Fields)> Items = new List<(string Key, (FieldInfo Info, object Value)[] Fields)>();
public static void Dispose(string Key)
{
for (int i = 0; i < Items.Count; i++)
{
if (Items[i].Key == Key)
{
Items.RemoveAt(i);
break;
}
}
}
public static bool? IsChanged(this object Value, string Key)
{
for (int i = 0; i < Items.Count; i++)
{
var Item = Items[i];
if (Item.Key == Key)
{
for (int j = 0; j < Item.Fields.Length; j++)
{
if (Item.Fields[j].Info.GetValue(Value) != Item.Fields[j].Value)
{
Item.Fields[j].Value = Item.Fields[j].Info.GetValue(Value);
return true;
}
}
return false;
}
}
var list = new List<(FieldInfo, object)>();
var Fields = Value.GetType().GetFields();
for (int i = 0; i < Fields.Length; i++)
{
list.Add((Fields[i], Fields[i].GetValue(Value)));
}
Items.Add((Key, list.ToArray()));
return null;
}
public static FieldInfo[] Track(this object Value, string Key)
{
for (int i = 0; i < Items.Count; i++)
{
var Item = Items[i];
if (Item.Key == Key)
{
var result = new List<FieldInfo>();
for (int j = 0; j < Item.Fields.Length; j++)
{
if (Item.Fields[j].Info.GetValue(Value) != Item.Fields[j].Value)
{
Item.Fields[j].Value = Item.Fields[j].Info.GetValue(Value);
result.Add(Item.Fields[j].Info);
}
}
if (result.Count > 0) { return result.ToArray(); }
}
}
var list = new List<(FieldInfo, object)>();
var Fields = Value.GetType().GetFields();
for (int i = 0; i < Fields.Length; i++)
{
list.Add((Fields[i], Fields[i].GetValue(Value)));
}
Items.Add((Key, list.ToArray()));
return null;
}
}
}
It's a pleasure to see how much knowledge people have on here, it's a treasure of a place.
I've seen myself writing code for DataGridView events - and using DataSource to a backend prepared DataTable object.
Sometimes the user can remove rows, update them etc. and the underlying data will need validation checks again.
Let's assume we have a person class
class Person {
public string FirstName { get; set; }
}
Let's say some other part of the code deals with creating an array of Person.
class Processor {
public static Person[] Create()
{
....
....
return person[];
}
}
And this information would appear on a DataGridView for user viewing.
I've tried something like this:
public static DataTable ToTable(List<Person> list)
{ ... }
And had this method in the Person class .. which I would think it'd belong to. Then I would bind the DataGridView to that DataTable and the user will then see that data and do their tasks.
But I've thought of using BindingList<> which I'm not so educated on yet.. would I still have the same capability of sorting the DataGridView like it does with DataTable as a DataSource? Would BindingList be implemented by a container class like "PersonCollection" or would the Person class implement itself? I would like to fire some events to be able to modify the collection in a clean way without having to reset datasources, etc. Where the user experience could really be affected.
I understand that modifying the DataSource DataTable is the good way. But sometimes I need to fire methods in the corresponding class that that specific row refers to, and had an ugly extra hidden column which would hold a reference to the existing object somewhere else (the Person reference).
If you guys know a better design solution, I would be more than happy to hear it.
Thanks in advance,
PS. After reading "The Pragmatic Programmer", I just can't stop thinking critically about code!
Leo B.
Create a business object class. Implement INotifyPropertyChanged. Look at the code below:
public class Employee:INotifyPropertyChanged
{
public Employee(string Name_, string Designation_, DateTime BirthDate_)
{
this.Name = Name_;
this.Designation = Designation_;
this.BirthDate = BirthDate_;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
[DisplayName("Employee Name")]
public string Name
{
get { return this._Name; }
set
{
if (value != this._Name)
{
this._Name = value;
NotifyPropertyChanged("Name");
}
}
}
private string _Name = string.Empty;
[DisplayName("Employee Designation")]
public string Designation
{
get { return this._Designation; }
set
{
if (value != this._Designation)
{
this._Designation = value;
NotifyPropertyChanged("Designation");
}
}
}
private string _Designation = string.Empty;
public DateTime BirthDate
{
get { return this._BirthDate; }
set
{
if (value != this._BirthDate)
{
this._BirthDate = value;
NotifyPropertyChanged("BirthDate");
}
}
}
private DateTime _BirthDate = DateTime.Today;
[DisplayName("Age")]
public int Age
{
get
{
return DateTime.Today.Year - this.BirthDate.Year;
}
}
}
Create your custom collection:
public class EmployeeCollection:BindingList<Employee>
{
public new void Add(Employee emp)
{
base.Add(emp);
}
public void SaveToDB()
{
//code to save to db
}
}
Set the data source:
_employeeStore = new EmployeeCollection();
this.dataGridView1.DataBindings.Add("DataSource", this, "EmployeeStore");
Now if you want to add an employee to your datagridview,
Employee employee = new Employee(textBoxName.Text, textBoxDesignation.Text, dateTimePicker1.Value);
_employeeStore.Add(employee);
This is very clean. You just play with business object and don't touch the UI.
Havent read you question fully, bbut you might want to take a look at my Project ModelShredder, which provides a convinient and fast ToDataTable method