File: MS\Internal\Documents\Application\ChainOfDependencies.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationUI\PresentationUI_r5prqfe0_wpftmp.csproj (PresentationUI)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
// Description:
// A Generic that provides user with the ability to chain dependent objects
// of a shared base type and perform actions on them in order of dependency.
 
namespace MS.Internal.Documents.Application
{
/// <summary>
/// A Generic that provides user with the ability to chain dependent objects
/// of a shared base type and perform actions on them in order of dependency.
/// </summary>
/// <remarks>
/// This is different from the chain of responsiblity in the following ways:
/// 
///  - Order of execution in the chain can be inversed by calling LastToFirst.
///  - The same operation is performed on each member once.
/// 
/// This class has many methods which are intentionaly recursive.  There is
/// currently no validation to prevent cyclic dependencies.  As the chain is
/// currently fixed at compile time there is no need; StackOverFlowException
/// durring testing is fine.
/// </remarks>
/// <typeparam name="T">A type common to all in the chain.</typeparam>
internal static class ChainOfDependencies<T> where T : IChainOfDependenciesNode<T>
{
    #region Internal Methods
    //--------------------------------------------------------------------------
    // Internal Methods
    //--------------------------------------------------------------------------
 
    /// <summary>
    /// Gets the last member in the chain. (The one with no dependencies.)
    /// </summary>
    /// <param name="member">The current member.</param>
    /// <returns>The last member in the chain. (The one with no dependencies.)
    /// </returns>
    internal static T GetLast(T member)
    {
        T last = member;
 
        if (member.Dependency != null)
        {
            last = GetLast(member.Dependency);
        }
 
        return last;
    }
 
    /// <summary>
    /// Will perform the action from the member with no dependencies to the most
    /// dependent member.
    /// </summary>
    /// <param name="member">The member on which to perform the action.</param>
    /// <param name="action">The action to perform on the member.</param>
    /// <returns>Returns true if all the actions returned true.</returns>
    internal static bool OrderByLeastDependent(
        T member,
        ChainOfDependencies<T>.Action action)
    {
        bool satisfied = true;
 
        T nextInChain = member.Dependency;
 
        if (nextInChain != null)
        {
            satisfied = OrderByLeastDependent(nextInChain, action);
        }
 
        if (satisfied)
        {
            satisfied = action(member);
        }
        else
        {
            Trace.SafeWrite(
                 Trace.File,
               "Dependency for {0}#{1} was not satisfied skipping action.",
                member.GetType(),
                member.GetHashCode());
        }
 
        return satisfied;
    }
 
    /// <summary>
    /// Will perform the action from most dependent to not dependent.
    /// </summary>
    /// <param name="member">The member on which to perform the action.</param>
    /// <param name="action">The action to perform on the member.</param>
    /// <returns>Returns true if the all the actions returned true.</returns>
    internal static bool OrderByMostDependent(
        T member,
        ChainOfDependencies<T>.Action action)
    {
        bool satisfied = action(member);
 
        T nextInChain = member.Dependency;
 
        if (satisfied)
        {
            if (nextInChain != null)
            {
                satisfied = OrderByMostDependent(nextInChain, action);
            }
        }
        else
        {
            Trace.SafeWrite(
                Trace.File,
                "Dependency for {0}#{1} was not satisfied skipping action.",
                member.GetType(),
                member.GetHashCode());
        }
 
        return satisfied;
    }
    #endregion Internal Methods
 
    #region Internal Delegates
    //--------------------------------------------------------------------------
    // Internal Delegates
    //--------------------------------------------------------------------------
 
    /// <summary>
    /// An action to perform on a ChainOfDependencies member.
    /// </summary>
    /// <param name="member">The member on which to perform the action.</param>
    /// <returns>True if the dependency was satisfied.</returns>
    internal delegate bool Action(T member);
    #endregion Internal Delegates
}
}