using System; namespace UniversalEditor { /// /// The type of comparison to use with the conditional statement. /// [Flags()] public enum ConditionComparison { /// /// Returns true if the two values are equal by value. /// Equal = 1, /// /// Returns true if the two values are equal by reference (or by value if they are value types). /// ReferenceEqual = 2, /// /// Returns true if the first value is greater than the second value. /// GreaterThan = 4, /// /// Returns true if the first value is less than the second value. /// LessThan = 8, /// /// Negates the conditional comparison. /// Not = 16 } /// /// The type of combination applied to a series of conditional statements. /// public enum ConditionCombination { /// /// Returns true if all of the conditional statements in this group are true. /// And, /// /// Returns true if at least one of the conditional statements in this group are true. /// Or, Xor } /// /// Defines the minimum functionality required to implement a conditional statement (either a /// itself or a of multiple /// s. /// public interface IConditionalStatement { /// /// Evaluates the conditional statement based on the given criteria. /// /// The set of values against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. bool Test(params System.Collections.Generic.KeyValuePair[] propertyValues); /// /// Evaluates the conditional statement based on the given criteria. /// /// The set of values against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. bool Test(System.Collections.Generic.Dictionary propertyValues); /// /// Evaluates the conditional statement based on the given criterion. /// /// The value against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. bool Test (object value); } /// /// A collection of s /// public class ConditionalStatementCollection : System.Collections.ObjectModel.Collection { } /// /// A group of s joined by a . /// public class ConditionGroup : IConditionalStatement { /// /// Creates a new with no conditional statements specified and a /// default of . /// public ConditionGroup() { // I know it's initialized to this but I'm doing it here for clarity's sake (and because // it's documented here... if you change it, make sure to update the documentation! don't // rely on the field initializer) mvarCombination = ConditionCombination.And; } /// /// Creates a new with the specified /// and s. /// /// The used to join s when testing this . /// The s and s that are part of this . public ConditionGroup(ConditionCombination combination, params IConditionalStatement[] statements) { mvarCombination = combination; for (int i = 0; i < statements.Length; i++) { mvarConditions.Add (statements[i]); } } private ConditionalStatementCollection mvarConditions = new ConditionalStatementCollection(); /// /// Gets all s in this . /// public ConditionalStatementCollection Conditions { get { return mvarConditions; } } private ConditionCombination mvarCombination = ConditionCombination.And; /// /// The type of combination used to join the s in this /// . /// public ConditionCombination Combination { get { return mvarCombination; } set { mvarCombination = value; } } /// /// Evaluates the conditional statement based on the given criteria. /// /// The set of values against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. public bool Test (params System.Collections.Generic.KeyValuePair[] propertyValues) { bool retval = false; if (mvarCombination == ConditionCombination.And) { retval = true; } for (int i = 0; i < mvarConditions.Count; i++) { switch (mvarCombination) { case ConditionCombination.And: retval &= mvarConditions[i].Test (propertyValues); break; case ConditionCombination.Or: retval |= mvarConditions[i].Test (propertyValues); break; case ConditionCombination.Xor: retval ^= mvarConditions[i].Test (propertyValues); break; } } return retval; } /// /// Evaluates the conditional statement based on the given criteria. /// /// The set of values against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. public bool Test(System.Collections.Generic.Dictionary propertyValues) { bool retval = false; if (mvarCombination == ConditionCombination.And) { retval = true; } for (int i = 0; i < mvarConditions.Count; i++) { switch (mvarCombination) { case ConditionCombination.And: retval &= mvarConditions[i].Test(propertyValues); break; case ConditionCombination.Or: retval |= mvarConditions[i].Test(propertyValues); break; case ConditionCombination.Xor: retval ^= mvarConditions[i].Test(propertyValues); break; } } return retval; } /// /// Evaluates the conditional statement based on the given criterion. /// /// The value against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. public bool Test (object value) { bool retval = true; for (int i = 0; i < mvarConditions.Count; i++) { switch (mvarCombination) { case ConditionCombination.And: retval &= mvarConditions[i].Test (value); break; case ConditionCombination.Or: retval |= mvarConditions[i].Test (value); break; case ConditionCombination.Xor: retval ^= mvarConditions[i].Test (value); break; } } return retval; } } public class Condition : IConditionalStatement { private string mvarPropertyName = String.Empty; /// /// The name of the property against which to test when the method is called /// passing in a property reference. /// public string PropertyName { get { return mvarPropertyName; } set { mvarPropertyName = value; } } private ConditionComparison mvarComparison = ConditionComparison.Equal; /// /// The type of comparison to use when testing this . /// public ConditionComparison Comparison { get { return mvarComparison; } set { mvarComparison = value; } } private object mvarValue = null; /// /// The value against which to test when the method is called. /// public object Value { get { return mvarValue; } set { mvarValue = value; } } /// /// Creates a with the specified property name, comparison, and value. /// /// The name of the property against which to test when the method is called passing in a property reference. /// The type of comparison to use. /// The value against which to test when the method is called. public Condition(string propertyName, ConditionComparison comparison, object value) { mvarPropertyName = propertyName; mvarComparison = comparison; mvarValue = value; } /// /// Evaluates the conditional statement based on the given criteria. /// /// The set of values against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. public bool Test(params System.Collections.Generic.KeyValuePair[] propertyValues) { bool retval = true; foreach (System.Collections.Generic.KeyValuePair propertyValue in propertyValues) { if (propertyValue.Key == mvarPropertyName) { retval &= Test(propertyValue.Value); } } return retval; } /// /// Evaluates the conditional statement based on the given criteria. /// /// The set of values against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. public bool Test(System.Collections.Generic.Dictionary propertyValues) { bool retval = true; foreach (System.Collections.Generic.KeyValuePair propertyValue in propertyValues) { if (propertyValue.Key == mvarPropertyName) { retval &= Test(propertyValue.Value); } } return retval; } /// /// Evaluates the conditional statement based on the given criterion. /// /// The value against which to evaluate the conditional statement. /// True if the conditions are satisfied; false otherwise. public bool Test (object propertyValue) { // would you like meatballs with your spaghetti code? bool returnValue = false; if ((mvarComparison & ConditionComparison.Equal) == ConditionComparison.Equal) { if (propertyValue == null) { // our comparison object is null, so we can't .Equals it // just do regular == with the constant null in that case returnValue |= (mvarValue == null); } else { returnValue |= (propertyValue.Equals(mvarValue)); } } if ((mvarComparison & ConditionComparison.ReferenceEqual) == ConditionComparison.ReferenceEqual) { if (propertyValue == null) { // our comparison object is null, so we can't .Equals it // just do regular == with the constant null in that case returnValue |= (mvarValue == null); } else { returnValue |= (propertyValue == mvarValue); } } if (((mvarComparison & ConditionComparison.GreaterThan) == ConditionComparison.GreaterThan) && (propertyValue is IComparable)) { if (propertyValue == null) { // can ANYTHING ever be greater than or less than null? returnValue |= false; } else { // we need to directly invoke IComparable.CompareTo here since we can't (usually) // do > or < on objects... not sure what to do if the object doesn't implement // IComparable though returnValue |= ((propertyValue as IComparable).CompareTo(mvarValue) > 0); } } if (((mvarComparison & ConditionComparison.LessThan) == ConditionComparison.LessThan) && (propertyValue is IComparable)) { if (propertyValue == null) { // can ANYTHING ever be greater than or less than null? returnValue |= false; } else { // we need to directly invoke IComparable.CompareTo here since we can't (usually) // do > or < on objects... not sure what to do if the object doesn't implement // IComparable though returnValue |= ((propertyValue as IComparable).CompareTo(mvarValue) < 0); } } if ((mvarComparison & ConditionComparison.Not) == ConditionComparison.Not) { // we have a Not in there, so negate our return value returnValue = !returnValue; } // did you have as much fun reading this as I did writing it? bool from_hell = returnValue; return from_hell; } } }