using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chernobyl.Event;
using Chernobyl.Utility;
namespace Chernobyl.Values
{
///
/// A basic implementation of an intended to make
/// the creation of easier.
///
/// The type held by .
public abstract class BasicValue : IValue
{
///
/// Initializes a new instance of the class.
///
protected BasicValue()
: this(EqualityComparer.Default)
{}
///
/// Initializes a new instance of the class.
///
/// The instance used to compare new and previous
/// values of to determine if
/// should be raised.
protected BasicValue(IEqualityComparer comparer)
{
Comparer = comparer;
}
///
/// An event that is raised immediately after the value held by this
/// instance has been modified.
///
public event EventHandler> Provide
{
add
{
ProvideHandler += value;
if (IsReady)
value(this, new ValueChangedEventArgs(PreviousValue, Value));
IsNeeded = true;
}
remove
{
ProvideHandler -= value;
if(ProvideHandler.GetInvocationList().Length == 0)
IsNeeded = false;
}
}
///
/// The value held by this instance. If the value has not yet been
/// provided it will be equal to default(T). Setting this property
/// will make this instance ready.
///
protected T Value
{
get
{
// Don't set IsNeeded to true since this property is protected
// and the only instances accessing the get of this property will
// be types who have control over readiness.
return BackingValue;
}
set
{
if (IsReady == false || Comparer.Equals(BackingValue, value) == false)
{
PreviousValue = BackingValue;
BackingValue = value;
// Setting IsReady to true when it was previously false will
// raise Provide. Otherwise, raise Provide since setting
// IsReady to true when it is already true will not raise
// Provide.
if (IsReady == false)
IsReady = true;
else if (ProvideHandler != null)
ProvideHandler(this, new ValueChangedEventArgs(PreviousValue, Value));
}
}
}
///
/// The backing property or implementation to . This
/// property should just set and get the value. The
/// property handles setting of and
/// and the raising of
/// .
///
protected abstract T BackingValue { get; set; }
///
/// The previous value of .
///
protected abstract T PreviousValue { get; set; }
///
/// The instance used to compare new and previous values of
/// to determine if should be
/// raised.
///
/// Thrown if the value set on
/// this property is null.
public IEqualityComparer Comparer
{
get { return _comparer; }
protected set
{
value.ThrowIfNull("value");
_comparer = value;
}
}
///
/// True if event handlers set on should be
/// invoked with the current value, false if otherwise. Setting this
/// property to true when it was previously false will cause the
/// event to be raised. This property is made true
/// when the is set. By default this property is false.
///
protected bool IsReady
{
get { return _isReady; }
set
{
if (_isReady != value)
{
_isReady = value;
if (_isReady && ProvideHandler != null)
ProvideHandler(this, new ValueChangedEventArgs(PreviousValue, Value));
}
}
}
///
/// Set to true when client code subscribes to the
/// event.
///
protected bool IsNeeded
{
get { return _isNeeded; }
set
{
if (_isNeeded != value)
{
_isNeeded = value;
if (_isNeeded)
Needed();
else
NotNeeded();
}
}
}
///
/// Invoked when is changed to true.
/// Implementations of this method should invoke the base class method.
///
protected virtual void Needed() { }
///
/// Invoked when is changed to false.
/// Implementations of this method should invoke the base class method.
///
protected virtual void NotNeeded() { }
///
/// The backing field to .
///
protected EventHandler> ProvideHandler { get; private set; }
///
/// The backing field to .
///
IEqualityComparer _comparer;
///
/// The backing field to .
///
bool _isReady;
///
/// The backing field to .
///
bool _isNeeded;
}
}