Skip to content

Instantly share code, notes, and snippets.

@philcockfield
Created August 7, 2012 19:57
Show Gist options
  • Save philcockfield/3288821 to your computer and use it in GitHub Desktop.
Save philcockfield/3288821 to your computer and use it in GitHub Desktop.
Auto Properties
/*
Copyright 2012, Mu.
MIT License.
http://www.opensource.org/licenses/mit-license.php/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the 'Software'), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel;
namespace Core
{
/*
Base class that provides storing, and notifications for
property changes.
*/
public abstract class AutoPropertyBase : DisposableBase
{
#region Head
public event ChangedEventHandler Changed;
public event ChangingEventHandler Changing;
private readonly Dictionary<string, object> propValues = new Dictionary<string, object>();
// Destruction.
protected override void Dispose(bool isDisposing)
{
propValues.Clear();
base.Dispose(isDisposing);
}
#endregion
#region Methods - Protected
/*
Retrieves the value for the calling property.
*/
protected T Get<T>(T defaultValue = default(T))
{
var key = getPropName(ReflectionUtil.GetCallingMethod(), "get_");
return getValue(key, defaultValue);
}
protected void Set<T>(T value, bool silent = false)
{
// Setup initial conditions.
var method = ReflectionUtil.GetCallingMethod();
var key = getPropName(method, "set_");
var oldValue = getValue<T>(key);
if (Equals(oldValue, value)) return; // No change.
// Pre-event.
if (silent != true && Changing != null) {
var args = new ChangingEventArgs(this, key, method, oldValue, value);
Changing(this, args);
// Don't continue if a listener cancelled the event.
if (args.Cancelled) return;
}
// Store value.
propValues[key] = value;
// Post-event.
if (silent != true && Changed != null) {
Changed(this, new ChangedEventArgs(this, key, method, oldValue, value));
}
//TODO
// - Fire on UI thread.
}
#endregion
#region Internal
private T getValue<T>(string key, T defaultValue = default(T))
{
if (propValues.ContainsKey(key)) {
return (T)propValues[key];
}
else {
return defaultValue;
}
}
private string getPropName(MethodBase method, string prefix)
{
var name = method.Name;
if (prefix.Length > name.Length || name.Substring(0, prefix.Length) != prefix)
throw new InvalidOperationException(String.Format(
"The method name [{0}] is not a property because it does not start with [{1}]",
name,
prefix));
return name.Substring(prefix.Length, name.Length - prefix.Length);
}
#endregion
}
}
namespace Core
{
// Delegates.
public delegate void ChangedEventHandler(object source, ChangedEventArgs e);
public delegate void ChangingEventHandler(object source, ChangingEventArgs e);
public class ChangeEventArgs : PropertyChangedEventArgs
{
object oldValue;
object newValue;
public ChangeEventArgs(object source, string name, MethodBase property, object oldValue, object newValue) : base(name)
{
Source = source;
Property = property;
OldValue = oldValue;
NewValue = newValue;
}
public object Source { get; private set; }
public MethodBase Property { get; private set; }
public object OldValue { get; private set; }
public object NewValue { get; private set; }
}
public class ChangedEventArgs : ChangeEventArgs
{
public ChangedEventArgs(object source, string name, MethodBase property, object oldValue, object newValue)
: base(source, name, property, oldValue, newValue)
{
}
}
public class ChangingEventArgs : ChangeEventArgs
{
public ChangingEventArgs(object source, string name, MethodBase property, object oldValue, object newValue)
: base(source, name, property, oldValue, newValue)
{
}
public bool Cancelled { get; set; }
public void Cancel(){ Cancelled = true; }
}
}
/*
Copyright 2012, Mu.
MIT License.
http://www.opensource.org/licenses/mit-license.php/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the 'Software'), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
using System.Reflection;
using System.Diagnostics;
namespace Core
{
public static class ReflectionUtil
{
/*
Retrieves the reflection of the calling method.
*/
public static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
/*
Retrieves the type of the calling method.
*/
public static Type GetCallingType()
{
return new StackFrame(2, false).GetMethod().DeclaringType;
}
}
}
class Foo : Model
{
public string Text
{
get { return Get<string>(); }
set { Set<string>(value); }
}
}
using System;
namespace Core
{
public class Model : AutoPropertyBase
{
public Model()
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment