I want to learn more about c#, and I've heard that you should use Private specifier and use get/set to make it public.
I got a small application that take textbox data and writes it to a file. And it encrypts the file.
But I can't graps the concept about getters and setters. Here is my one of my classes and Methods that writes to a file.
class MyClass
{
public static bool WriteToFile(string text)
{
string FileName = "C:\\crypt\\crypt.txt";
try
{
using (System.IO.StreamWriter WriteToFile = new System.IO.StreamWriter(FileName))
{
WriteToFile.Write(text);
WriteToFile.Close();
}
return true;
}
catch
{
return false;
}
}
But instead i want to use a property. How should i do it?
This is how i pass in the textbox-data from my main class.
public void button1_Click(object sender, EventArgs e)
{
MyClass c = new MyClass();
if (MyClass.WriteToFile(textBox1.Text))
MessageBox.Show("success, managed to write to the file");
else
MessageBox.Show("Error, Could not write to file. Please check....");
I've looked at various tutorials such as https://channel9.msdn.com/series/C-Fundamentals-for-Absolute-Beginners/15 and tutorials, but I really stuggling.
WriteToFile is a method.
Methods are methods, and properties are properties.
Methods encapsulate behaviour, while properties encapsulate state.
WriteToFile should not be a property, because it does not encapsulate state. In fact, it attempts to write into the file system.
An example of a property would be:
public class MyClass
{
private bool _canWrite;
/// Checks whether the file can be written into the file system
public bool CanWrite
{
get { return _canWrite; }
}
}
From another class, you would call it like this:
if(myClass.CanWrite)
{
// ...
}
Notice that CanWrite does not define any behaviour, it just defines a getter for the _canWrite field, this ensures that external classes don't get to see too much about your class.
Also notice that I define a getter only, this prevents others from setting your property.
There is not much to change to your design besides one little thing. But first things first:
Could you place that code into a property? Sure. Should you? Not at all. Your method WriteToFile is actually doing sth. and thats what methods are for. Properties on the other hand are used for modifying/storing data.
Thats why property-names sound more like Names while method-names generally sound like Commands:
Example
public class Sample
{
private string someText;
// This Property Stores or modifies SomeText
public string SomeText
{
get { return this.someText; }
set { this.someText = value; }
}
// Method that does sth. (writes sometext to a given File)
public void WriteSomeTextToFile(string File)
{
// ...
}
}
Why properties/modifiers?
it is considered good pratice to encapsulate data within propeties like in the example above. A small improvement could be the use of an AutoProperty like so:
public string SomeText { get; set; }
which basically results in the same structure as the combination of an encapsulated field like in the first example.
Why?: because this makes it easy to switch it out or to add logic to your get/set-operations.
For example, you could add validation:
public string SomeText
{
// ...
set
{
if (value.Length > 100)
throw new Exception("The given text is to long!");
this.someText = value;
}
}
SideNote: Possible improvement to your class
The only improvement I could think of is not to swallow the exception in your write method:
public void WriteToFile()
{
using (var fileWriter= new System.IO.StreamWriter(FileName))
{
fileWriter.Write(_text);
fileWriter.Close();
}
}
This is much cleaner and you would not have to "decision" cascades handling the same issue (your try/catch and if/else) are practically doing the same.
public void button1_Click(object sender, EventArgs e)
{
try
{
var c = new MyClass();
c.WriteToFile(textBox1.Text))
MessageBox.Show("success, managed to write to the file");
}
catch(Exception e)
{
MessageBox.Show("Error, Could not write to file. " + e.Message);
}
}
This way, you do not only have the same behaviour, but you also have more information than just the raw fact that your operation was unsuccessful (false)
Okay so I think for you case you don't need a property, but if we assume you wan't to create some kind of wrapper class that handles all your writing to files you could do something along the lines of
class AwesomeFileWriter
{
private const string FileName = "C:\\crypt\\crypt.txt";
private readonly string _text;
public AwesomeFileWriter(string text)
{
_text = text;
}
public bool WriteToFile()
{
try
{
using (System.IO.StreamWriter WriteToFile = new System.IO.StreamWriter(FileName))
{
WriteToFile.Write(_text);
WriteToFile.Close();
}
return true;
}
catch
{
return false;
}
}
}
Without actually showing you the code I'll try and explain getters and setters so you can understand their concept.
A property looks like a method to the internal class and field to an external class.
E.g. You are able to perform logic in your property whereas when you call the property from a different class it behaves just like any other field.
GET: Used to retrieve and return a property. You are able to perform some complex logic before actually returning your property. You are able to safely expose private variables via the Get without compromising on writing.
SET: Used to set the value of a property that may be private, constant or public. You are able to have control over the setting of the variable.
Usually properties are used to keep values as attributes; characteristics; settings.
Methods and functions you would think as actions.
e.g as shown below:
public class MyClass{
/// <summary>
/// Keeps the file name
/// </summary>
public string FileName { get; set; }
/// <summary>
/// Action to write the file
/// </summary>
/// <returns>Returns true if the info. was wrote into the file.</returns>
public bool WriteToFileSucceed()
{
try
{
using (System.IO.StreamWriter WriteToFile = new System.IO.StreamWriter(FileName))
{
WriteToFile.Write(text);
WriteToFile.Close();
}
return true;
}
catch
{
return false;
}
}}
...
public void button1_Click(object sender, EventArgs e){
MyClass myClass = new MyClass();
myClass.FileName = #"C:\crypt\crypt.txt";
if(myClass.WriteToFileSucceed())
{
MessageBox.Show("Success, managed to write to the file");
}
else
{
MessageBox.Show("Ops! Unable to write to the file.");
}}
Related
given this delegate
public class XYZ
{
public static Action<Profile> DoSomething = (profile) =>
{
//some default code here
return;
};
}
at some time in my main execution I override it with this:
XYZ.DoSomething = (currProfile) =>
{
// some overriding code here
}
How do I set the code back to the original default code when I need to without duplicating code?
Here's a good reason to never use public fields...
Once you set it; its gone. You can hold onto the original value though:
var originalAction = XYZ.DoSomething;
XYZ.DoSomething = ...;
XYZ.DoSomething = originalAction;
Usually it is a bad idea to rely on client code to handle this however; so if I was writing it I would expose as a property like so:
public Action<X> DoSomethingOverride {get; set;}
public Action<X> DoSomething => doSomethingOverride ?? DefaultMethod;
private void DefaultMethod (X param)
{
}
There are a number of other ways to handle this, but all involve storing off the original method. All good ways to handle this will use a property to ensure that only the declaring class is actually setting the DoSomething method and that resetting to the default is possible.
Total aside; since this is static setting the action will affect everything that uses this class. This is asking for bugs later; don't do that.
Maybe somthing like this?
public static Action<Profile> _doSomethingBase = (profile) =>
{
//some default code here
return;
};
public static Action<Profile> _doSomething = _doSomethingBase;
public static Action<Profile> DoSomething
{
get => _doSomething;
set => _doSomething = value;
}
public static void RevertDoSomething()
{
DoSomething = _doSomethingBase;
}
Consider the following example:
public class Foo
{
private string _text;
[BsonElement("text"), BsonRequired]
public string Text
{
get { return _text; }
set
{
_text = value;
Bar(_text);
}
}
private void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
}
The setter of the Text property and, subsequently, the method Bar are called both when the user of the class assigns a new value to the property and during object deserialization by the MongoDB C# driver. What I need is to ensure that Bar is called only when the Text property is set by the user and not during deserialization.
I see two solutions which don't really suit me:
The first is to move the BsonElement attribute to the backing field. However, as far as I know, the BsonElement attribute is used in query building by the MongoDB C# driver, so I will lose the ability to use the Text property in queries.
The second solution is to make the Text setter private and add a method through which the user of the class will set the Text property, and in which the Bar method would be called. However, the Text setter is used very often in the existing solution, and I'm a bit reluctant to change 70+ calls across all files. Plus, the code will become less readable.
Is there any cleaner way to separate deserialization and user-prompted property change while retaining the BsonElement attribute on the property?
I know this question is old, but I'd still like to help for other people stumbling on this issue as I have done.
It basically boils down to something very simple: serialization and deserialization are not limited to public fields and properties!
The next example will cover the original question without having to invent dubious secondary properties:
public class Foo
{
[BsonElement("Text"), BsonRequired]
private string _text;
[BsonIgnore]
public string Text
{
get { return _text; }
set
{
_text = value;
Bar(_text);
}
}
private void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
}
Simply put your BsonElement class on the backing field and tell it to BsonIgnore the property.
You can do whatever you like in the getter and setter without having to worry about deserialization which now occurs on private field level.
Hope this helps somebody!
Why not create a seperate property for the users and for the DB for the same private variable, something like this,
public class Foo
{
private string _text;
[BsonElement("text"), BsonRequired]
public string TextDB
{
get { return _text; }
set
{
_text = value;
}
}
[BsonIgnore]
public string Text
{
get { return _text; }
set
{
_text = value;
Bar(_text);
}
}
private void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
}
You can use a little trick an implement a kind of property listener.
The usage would be:
// Working with some foo here...
var foo = new Foo();
foo.Text = "Won't fire anything";
using (var propertyListener = new FooPropertiesListener(foo))
{
foo.Text = "Something will fire you listener";
}
// Some more work with foo here...
foo.Text = "Won't fire anything";
And the implementation behind it, something like:
FooPropertiesListener
public class FooPropertiesListener : IDisposable
{
private readonly Foo Foo;
public FooPropertiesListener(Foo foo)
{
this.Foo = foo;
this.Foo.PropertiesListener = this;
}
public void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
public void Dispose()
{
Foo.PropertiesListener = null;
}
}
Foo
public class Foo
{
internal FooPropertiesListener PropertiesListener;
private string _text;
[BsonElement("text"), BsonRequired]
public string Text
{
get { return _text; }
set
{
_text = value;
if (PropertiesListener != null)
{
PropertiesListener.Bar(_text);
}
}
}
}
I have a class with like 20 fields which get populated from SQL database on load. Currently I am calling load data method right after the constructor, which calls SQL proc and populate all the required fields. At times, I may not access the these 20 fields at all, I am adding additional cost of SQL call even though it was not required. So I changed all the properties to have an associated private property and when the program calls the public property, first I check the private property and if it is null that means we need to load data from sql so I call the load method. It works great, but when I see the code, there is a repeated pattern of null check and load the sql query. Is there a better way of doing this?
private string _name;
public string Name
{
get {
if (_name == null)
LoadData(); //this popultes not just but all the properties
return _name;
}
}
Btw C# now has default lazy-loaders implementation. Why not to use it, instead of providing isSomethingLoaded flags? :)
public class Bar
{
private Lazy<string> _name = new Lazy<string>(() => LoadString());
public string Name
{
get { return _name.Value; }
}
}
In case of non-static LoadString method, lazy-loader should be initialized in constructor;
Nope, this is right. Here is the wikipedia article. The overhead of the null check will be very minimal compared to unnecessary database calls. Now, if the users of the program actually use the values 99% of the time, then I would say this pattern is not needed.
Just one note of caution: If any of your values could possibly be null, then you will make unnecessary database calls. It might be better to do something like this (which will be an even quicker check since it is just a bit check):
//Constructor default to not loaded
bool isLoaded = false;
private string _name;
public string Name
{
get {
if (!isLoaded)
LoadData(); //this popultes not just but all the properties
return _name;
}
}
private LoadData()
{
//Load Data
isLoaded = true;
}
Well you could change it to:
if (!initialized)
LoadData();
And in your LoadData set initialized to true, but that really doesn't change the semantics of it.
One thing you can do is to extract if into separate method so each property contains just one additional call:
void EnsureData()
{
if (!dataLoaded)
LoadData(); //this populates all the properties
}
public string Name {
get {
EnsureData();
return _name;
}
}
I think you should consider your application structure. Why would you even instantiate the class if you are not going to be using the properties? I believe it's actually cleaner for you to call the SQL after your constructor code but only create the objects of your class if you are going to be using it. The other more flexible solution is making the LoadData public and calling it as needed from the object instance as needed.
I am in the learning process of design patterns. i have one suggestion if you load data only once you can try with singleton design pattern.
public class Singleton123
{
private static readonly string _property1 = ClassLoadData.LoadData();
public static string MyProperty1
{
get
{
return _property1;
}
}
}
public class ClassLoadData
{
public static string LoadData()
{
// any logic to load data
return "test";
}
}
Call property as below
Singleton123 obj = new Singleton123();
string stra = Singleton123.MyProperty1;
string strb = Singleton123.MyProperty1;
this property will be loaded only once.
The following is a simple example of an enum which defines the state of an object and a class which shows the implementation of this enum.
public enum StatusEnum
{
Clean = 0,
Dirty = 1,
New = 2,
Deleted = 3,
Purged = 4
}
public class Example_Class
{
private StatusEnum _Status = StatusEnum.New;
private long _ID;
private string _Name;
public StatusEnum Status
{
get { return _Status; }
set { _Status = value; }
}
public long ID
{
get { return _ID; }
set { _ID = value; }
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
}
when populating the class object with data from the database, we set the enum value to "clean". with the goal of keeping most of the logic out of the presentation layer, how can we set the enum value to "dirty" when a property is changed.
i was thinking something along the lines of;
public string Name
{
get { return _Name; }
set
{
if (value != _Name)
{
_Name = value;
_Status = StatusEnum.Dirty;
}
}
}
in the setter of each property of the class.
does this sound like a good idea, does anyone have any better ideas on how the dirty flag can be assigned without doing so in the presentation layer.
When you really do want a dirty flag at the class level (or, for that matter, notifications) - you can use tricks like below to minimise the clutter in your properties (here showing both IsDirty and PropertyChanged, just for fun).
Obviously it is a trivial matter to use the enum approach (the only reason I didn't was to keep the example simple):
class SomeType : INotifyPropertyChanged {
private int foo;
public int Foo {
get { return foo; }
set { SetField(ref foo, value, "Foo"); }
}
private string bar;
public string Bar {
get { return bar; }
set { SetField(ref bar, value, "Bar"); }
}
public bool IsDirty { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void SetField<T>(ref T field, T value, string propertyName) {
if (!EqualityComparer<T>.Default.Equals(field, value)) {
field = value;
IsDirty = true;
OnPropertyChanged(propertyName);
}
}
protected virtual void OnPropertyChanged(string propertyName) {
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You might also choose to push some of that into an abstract base class, but that is a separate discussion
One option is to change it on write; another is to keep a copy of all the original values and compute the dirtiness when anyone asks for it. That has the added benefit that you can tell exactly which fields have changed (and in what way) which means you can issue minimal update statements and make merge conflict resolution slightly easier.
You also get to put all the dirtiness-checking in one place, so it doesn't pollute the rest of your code.
I'm not saying it's perfect, but it's an option worth considering.
If you want to implement it in this way, and you want to reduce the amount of code, you might consider applying Aspect Oriented Programming.
You can for instance use a compile-time weaver like PostSharp , and create an 'aspect' that can be applied to properties. This aspect then makes sure that your dirty flag is set when appropriate.
The aspect can look like this:
[Serializable]
[AttributeUsage(AttributeTargets.Property)]
public class ChangeTrackingAttribute : OnMethodInvocationAspect
{
public override void OnInvocation( MethodInvocationEventArgs e )
{
if( e.Delegate.Method.ReturnParameter.ParameterType == typeof(void) )
{
// we're in the setter
IChangeTrackable target = e.Delegate.Target as IChangeTrackable;
// Implement some logic to retrieve the current value of
// the property
if( currentValue != e.GetArgumentArray()[0] )
{
target.Status = Status.Dirty;
}
base.OnInvocation (e);
}
}
}
Offcourse, this means that the classes for which you want to implement ChangeTracking, should implement the IChangeTrackable interface (custom interface), which has at least the 'Status' property.
You can also create a custom attribute ChangeTrackingProperty, and make sure that the aspect that has been created above, is only applied to properties that are decorated with this ChangeTrackingProperty attribute.
For instance:
public class Customer : IChangeTrackable
{
public DirtyState Status
{
get; set;
}
[ChangeTrackingProperty]
public string Name
{ get; set; }
}
This is a little bit how I see it.
You can even make sure that PostSharp checks at compile-time whether classes that have properties that are decorated with the ChangeTrackingProperty attribute, implement the IChangeTrackable interface.
This method is based on a set of different concepts provided in this thread. I thought i'd put it out there for anyone that is looking for a way to do this cleanly and efficiently, as i was myself.
The key of this hybrid concept is that:
You don't want to duplicate the data to avoid bloating and resource hogging;
You want to know when the object's properties have changed from a given original/clean state;
You want to have the IsDirty flag be both accurate, and require little processing time/power to return the value; and
You want to be able to tell the object when to consider itself clean again. This is especially useful when building/working within the UI.
Given those requirements, this is what i came up with, and it seems to be working perfectly for me, and has become very useful when working against UIs and capturing user changes accurately. I have also posted an "How to use" below to show you how I use this in the UI.
The Object
public class MySmartObject
{
public string Name { get; set; }
public int Number { get; set; }
private int clean_hashcode { get; set; }
public bool IsDirty { get { return !(this.clean_hashcode == this.GetHashCode()); } }
public MySmartObject()
{
this.Name = "";
this.Number = -1;
MakeMeClean();
}
public MySmartObject(string name, int number)
{
this.Name = name;
this.Number = number;
MakeMeClean();
}
public void MakeMeClean()
{
this.clean_hashcode = this.Name.GetHashCode() ^ this.Number.GetHashCode();
}
public override int GetHashCode()
{
return this.Name.GetHashCode() ^ this.Number.GetHashCode();
}
}
It's simple enough and addresses all of our requirements:
The data is NOT duplicated for the dirty check...
This takes into account all property changes scenarios (see scenarios below)...
When you call the IsDirty property, a very simple and small Equals operation is performed and it is fully customizable via the GetHashCode override...
By calling the MakeMeClean method, you now have a clean object again!
Of course you can adapt this to encompass a bunch of different states... it's really up to you. This example only shows how to have a proper IsDirty flag operation.
Scenarios
Let's go over some scenarios for this and see what comes back:
Scenario 1
New object is created using empty constructor,
Property Name changes from "" to "James",
call to IsDirty returns True! Accurate.
Scenario 2
New object is created using paramters of "John" and 12345,
Property Name changes from "John" to "James",
Property Name changes back from "James" to "John",
Call to IsDirty returns False. Accurate, and we didn't have to duplicate the data to do it either!
How to use, a WinForms UI example
This is only an example, you can use this in many different ways from a UI.
Let's say you have a two forms ([A] and [B]).
The first([A]) is your main form, and the second([B]) is a form that allows the user to change the values within the MySmartObject.
Both the [A] and the [B] form have the following property declared:
public MySmartObject UserKey { get; set; }
When the user clicks a button on the [A] form, an instance of the [B] form is created, its property is set and it is displayed as a dialog.
After form [B] returns, the [A] form updates its property based on the [B] form's IsDirty check. Like this:
private void btn_Expand_Click(object sender, EventArgs e)
{
SmartForm form = new SmartForm();
form.UserKey = this.UserKey;
if(form.ShowDialog() == DialogResult.OK && form.UserKey.IsDirty)
{
this.UserKey = form.UserKey;
//now that we have saved the "new" version, mark it as clean!
this.UserKey.MakeMeClean();
}
}
Also, in [B], when it is closing, you can check and prompt the user if they are closing the form with unsaved changes in it, like so:
private void BForm_FormClosing(object sender, FormClosingEventArgs e)
{
//If the user is closing the form via another means than the OK button, or the Cancel button (e.g.: Top-Right-X, Alt+F4, etc).
if (this.DialogResult != DialogResult.OK && this.DialogResult != DialogResult.Ignore)
{
//check if dirty first...
if (this.UserKey.IsDirty)
{
if (MessageBox.Show("You have unsaved changes. Close and lose changes?", "Unsaved Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
e.Cancel = true;
}
}
}
As you can see from the examples above, this can be a very useful thing to have since it really streamlines the UI.
Caveats
Every time you implement this, you have to customize it to the object you're using. E.g.: there's no "easy" generic way of doing this without using reflection... and if you use reflection, you lose efficiency, especially in large and complex objects.
Hopefully this helps someone.
Take a look at PostSharp (http://www.postsharp.org/).
You can easily create a Attribute which marks it as dirty you can add the attrubute to each property that needs it and it keeps all your code in one place.
Roughly speaking Create an interface which has your status in make the class implement it.
Create an attribute which can be applied on properties and cast to your interface in order to set the value when something changes one of the marked properties.
Your approach is basically how I would do it. I would just
remove the setter for the Status property:
public StatusEnum Status
{
get { return _Status; }
// set { _Status = value; }
}
and instead add a function
public SetStatusClean()
{
_Status = StatusEnum.Clean;
}
As well as SetStatusDeleted() and SetStatusPurged(), because I find it better indicates the intention.
Edit
Having read the answer by Jon Skeet, I need to reconsider my approach ;-) For simple objects I would stick with my way, but if it gets more complex, his proposal would lead to much better organised code.
If your Example_Class is lightweight, consider storing the original state and then comparing the current state to the original in order to determine the changes. If not your approach is the best because stroing the original state consumes a lot of system resources in this case.
Apart from the advice of 'consider making your type immutable', here's something I wrote up (and got Jon and Marc to teach me something along the way)
public class Example_Class
{ // snip
// all properties are public get and private set
private Dictionary<string, Delegate> m_PropertySetterMap;
public Example_Class()
{
m_PropertySetterMap = new Dictionary<string, Delegate>();
InitializeSettableProperties();
}
public Example_Class(long id, string name):this()
{ this.ID = id; this.Name = name; }
private void InitializeSettableProperties()
{
AddToPropertyMap<long>("ID", value => { this.ID = value; });
AddToPropertyMap<string>("Name", value => { this.Name = value; });
}
// jump thru a hoop because it won't let me cast an anonymous method to an Action<T>/Delegate
private void AddToPropertyMap<T>(string sPropertyName, Action<T> setterAction)
{ m_PropertySetterMap.Add(sPropertyName, setterAction); }
public void SetProperty<T>(string propertyName, T value)
{
(m_PropertySetterMap[propertyName] as Action<T>).Invoke(value);
this.Status = StatusEnum.Dirty;
}
}
You get the idea.. possible improvements: Use constants for PropertyNames & check if property has really changed.
One drawback here is that
obj.SetProperty("ID", 700); // will blow up int instead of long
obj.SetProperty<long>("ID", 700); // be explicit or use 700L
Here is how i do it.
In cases where i do not need to test for specific fields being dirty,
I have an abstract class:
public abstract class SmartWrap : ISmartWrap
{
private int orig_hashcode { get; set; }
private bool _isInterimDirty;
public bool IsDirty
{
get { return !(this.orig_hashcode == this.GetClassHashCode()); }
set
{
if (value)
this.orig_hashcode = this.orig_hashcode ^ 108.GetHashCode();
else
MakeClean();
}
}
public void MakeClean()
{
this.orig_hashcode = GetClassHashCode();
this._isInterimDirty = false;
}
// must be overridden to return combined hashcodes of fields testing for
// example Field1.GetHashCode() ^ Field2.GetHashCode()
protected abstract int GetClassHashCode();
public bool IsInterimDirty
{
get { return _isInterimDirty; }
}
public void SetIterimDirtyState()
{
_isInterimDirty = this.IsDirty;
}
public void MakeCleanIfInterimClean()
{
if (!IsInterimDirty)
MakeClean();
}
/// <summary>
/// Must be overridden with whatever valid tests are needed to make sure required field values are present.
/// </summary>
public abstract bool IsValid { get; }
}
}
As well as an interface
public interface ISmartWrap
{
bool IsDirty { get; set; }
void MakeClean();
bool IsInterimDirty { get; }
void SetIterimDirtyState();
void MakeCleanIfInterimClean();
}
This allows me to do partial saves, and preserve the IsDirty state if there is other details to save. Not perfect, but covers a lot of ground.
Example of usage with interim IsDirty State (Error wrapping and validation removed for clarity):
area.SetIterimDirtyState();
if (!UpdateClaimAndStatus(area))
return false;
area.MakeCleanIfInterimClean();
return true;
This is good for most scenarios, however for some classes i want to test for each field with a backing field of original data, and either return a list of changes or at least an enum of fields changed.
With an enum of fields changed i can then push that up through a message chain for selective update of fields in remote caches.
You could also think about boxing your variables, which comes at a performance cost, but also has its merits. It is pretty consise and you cannot accidentally change a value without setting your dirty status.
public class Variable<T>
{
private T _value;
private readonly Action<T> _onValueChangedCallback;
public Variable(Action<T> onValueChangedCallback, T value = default)
{
_value = value;
_onValueChangedCallback = onValueChangedCallback;
}
public void SetValue(T value)
{
if (!EqualityComparer<T>.Default.Equals(_value, value))
{
_value = value;
_onValueChangedCallback?.Invoke(value);
}
}
public T GetValue()
{
return _value;
}
public static implicit operator T(Variable<T> variable)
{
return variable.GetValue();
}
}
and then hook in a callback that marks your class as dirty.
public class Example_Class
{
private StatusEnum _Status = StatusEnum.New;
private Variable<long> _ID;
private Variable<string> _Name;
public StatusEnum Status
{
get { return _Status; }
set { _Status = value; }
}
public long ID => _ID;
public string Name => _Name;
public Example_Class()
{
_ID = new Variable<long>(l => Status = StatusEnum.Dirty);
_Name = new Variable<string>(s => Status = StatusEnum.Dirty);
}
}
Another method is to override the GetHashCode() method to somthing like this:
public override int GetHashCode() // or call it GetChangeHash or somthing if you dont want to override the GetHashCode function...
{
var sb = new System.Text.StringBuilder();
sb.Append(_dateOfBirth);
sb.Append(_marital);
sb.Append(_gender);
sb.Append(_notes);
sb.Append(_firstName);
sb.Append(_lastName);
return sb.ToString.GetHashCode();
}
Once loaded from the database, get the hash code of the object. Then just before you save check if the current hash code is equal to the previous hash code. if they are the same, don't save.
Edit:
As people have pointed out this causes the hash code to change - as i use Guids to identify my objects, i don't mind if the hashcode changes.
Edit2:
Since people are adverse to changing the hash code, instead of overriding the GetHashCode method, just call the method something else. The point is detecting a change not whether i use guids or hashcodes for object identification.
I'm not sure if I am abusing Enums here. Maybe this is not the best design approach.
I have a enum which declares the possible parameters to method which executes batch files.
public enum BatchFile
{
batch1,
batch2
}
I then have my method:
public void ExecuteBatch(BatchFile batchFile)
{
string batchFileName;
...
switch (batchFile)
{
case BatchFile.batch1:
batchFileName = "Batch1.bat";
break;
case BatchFile.batch2:
batchFileName = "Batch2.bat";
break;
default:
break;
}
...
ExecuteBatchFile(batchFileName);
}
So I was wondering if this is sound design.
Another option I was thinking was creating a Dictionary<> in the constructor like this:
Dictionary<BatchFile, String> batchFileName = new Dictionary<BatchFile, string>();
batchFileName.Add(BatchFile.batch1, "batch1.bat");
batchFileName.Add(BatchFile.batch2, "batch2.bat");
Then instead of using a switch statement I would just go:
public void ExecuteBatch(BatchFile batchFile)
{
ExecuteBatchFile(batchFileName[batchFile]);
}
I'm guessing the latter is the better approach.
I'd probably go for a design along these lines:
public interface IBatchFile
{
void Execute();
}
public class BatchFileType1 : IBatchFile
{
private string _filename;
public BatchFileType1(string filename)
{
_filename = filename;
}
...
public void Execute()
{
...
}
}
public class BatchFileType2 : IBatchFile
{
private string _filename;
public BatchFileType2(string filename)
{
_filename = filename;
}
...
public void Execute()
{
...
}
}
In fact, I'd extract any common functionality into a BatchFile base class
What if you suddenly need a third batch file? You have to modify your code, recompile your library and everybody who uses it, has to do the same.
Whenever I find myself writing magic strings that might change, I consider putting them into an extra configuration file, keeping the data out of the code.
I would personally use a static class of constants in this case:
public static class BatchFiles
{
public const string batch1 = "batch1.bat";
public const string batch2 = "batch2.bat";
}
If you want to use an enum then you may want to consider utilising attributes so you can store additional inforation (such as the file name) against the elements.
Here's some sample code to demonstrate how to declare the attributes:
using System;
public enum BatchFile
{
[BatchFile("Batch1.bat")]
batch1,
[BatchFile("Batch2.bat")]
batch2
}
public class BatchFileAttribute : Attribute
{
public string FileName;
public BatchFileAttribute(string fileName) { FileName = fileName; }
}
public class Test
{
public static string GetFileName(Enum enumConstant)
{
if (enumConstant == null)
return string.Empty;
System.Reflection.FieldInfo fi = enumConstant.GetType().GetField(enumConstant.ToString());
BatchFileAttribute[] aattr = ((BatchFileAttribute[])(fi.GetCustomAttributes(typeof(BatchFileAttribute), false)));
if (aattr.Length > 0)
return aattr[0].FileName;
else
return enumConstant.ToString();
}
}
To get the file name simply call:
string fileName = Test.GetFileName(BatchFile.batch1);
I think the latter approach is better because it separates out concerns. You have a method which is dedicated to associating the enum values with a physical path and a separate method for actually executing the result. The first attempt mixed these two approaches slightly.
However I think that using a switch statement to get the path is also a valid approach. Enums are in many ways meant to be switched upon.
Using enums is ok if you don't need to add new batch files without recompiling / redeploying your application... however I think most flexible approach is to define a list of key / filename pairs in your config.
To add a new batch file you just add it to the config file / restart / tell your user the key. You just need to handle unknown key / file not found exceptions.
Is it really necessary that ExecuteBatch works on limited number of possible file names only?
Why don't you just make it
public void ExecuteBatch(string batchFile)
{
ExecuteBatchFile(batchFile);
}
The problem with the latter case is if something passed an invalid value that is not inside the dictionary. The default inside the switch statement provides an easy way out.
But...if you're enum is going to have a lot of entries. Dictionary might be a better way to go.
Either way, I'd recommend some way to provide protection of the input value from causing a bad error even in ammoQ's answer.
The second approach is better, because it links the batch file objects (enums) with the strings..
But talking about design, it would not be very good to keep the enum and the dictionary separate; you could consider this as an alternative:
public class BatchFile {
private batchFileName;
private BatchFile(String filename) {
this.batchFileName = filename;
}
public const static BatchFile batch1 = new BatchFile("file1");
public const static BatchFile batch2 = new BatchFile("file2");
public String getFileName() { return batchFileName; }
}
You can choose to keep the constructor private, or make it public.
Cheers,
jrh.
The first solution (the switch) is simple and straight forward, and you really don't have to make it more complicated than that.
An alternative to using an enum could be to use properties that returns instances of a class with the relevant data set. This is quite expandable; if you later on need the Execute method to work differently for some batches, you can just let a property return a subclass with a different implementation and it's still called in the same way.
public class BatchFile {
private string _fileName;
private BatchFile(string fileName) {
_fileName = fileName;
}
public BatchFile Batch1 { get { return new BatchFile("Batch1.bat"); } }
public BatchFile Batch2 { get { return new BatchFile("Batch2.bat"); } }
public virtual void Execute() {
ExecuteBatchFile(_fileName);
}
}
Usage:
BatchFile.Batch1.Execute();