C# Deferred Property Setting

Asked by At

I am working on a project where I need to queue up a number of property changes. Let say I have:

public class foo
{
   string bar { get; set; }
   int bar1 { get; set }
}

I want to have some code that looks like:

//Store value set actions in a queue
foo.SetValue(bar, "abc");
foo.SetValue(bar1, 123);

//Preview changes
foreach(Item change in foo.ChangeQueue)
{
   Console.Write(change.PropertyName.ToString());
   Console.Write(change.Value.ToString());
}

//Apply actions
foo.CommitChanges();

What is the best way to accomplish this?

2 Answers

1
Community On Best Solutions

"Type-safe" version which uses callbacks. This will not automatically remove duplicate-settings. It also does not use reflection and so property-name errors will fail on compilation. This method could be expanded to require a "name" and remove duplicates by using a Dictionary backing (as per Akash's answer) or allow the "setter" to return a value (such as success or failure or the old value, or whatnot).

interface Setter {
    void Apply();
}
class Setter<T> : Setter {
    public T Data;
    public Action<T> SetFn;
    public void Apply() {
        SetFn(Data);
    }
}

List<Setter> changeQueue = new List<Setter>();

void SetValue<T>(Action<T> setFn, T data){
    changeQueue.Add(new Setter<T> {
        Data = data,
        SetFn = setFn,   
    });
}

void ApplyChanges(){
    foreach (var s in changeQueue){
        s.Apply();
    }
}

// .. later on
SetValue(x => System.Console.WriteLine(x), "hello world!");
ApplyChanges();

This method can also be trivially used "outside" the objects being monitored because all the operations are in potential closures.

Happy coding.

2
Akash Kava On

You can use Dictionary<string,object> as ChangeQueue to store your values.

You can iterate as,

foreach(KeyValuePair<string,object> item in ChangeQueue){
   Console.WriteLine(item.Key);// name of property
   Console.WriteLine(item.Value); // value of property
}


public void SetValue(string name, object value){
   PropertyInfo p = this.GetType().GetProperty(name);

   // following convert and raise an exception to preserve type safety
   ChangeQueue[name] = Convert.ChangeType(value,p.PropertyType);
}

public void ApplyChanges(){
   foreach(KeyValuePair<string,object> item in ChangeQueue){
      PropertyInfo p = this.GetType().GetProperty(item.Key);
      p.SetValue(this, item.Value, null);
   }
}