Pattern Binder - BinderDirector - C# — thumbnail

Very usefull in ressource aggregation, here you will find a code snippet that can be integrated in Inversion Of Control pattern using Interface Segregation Principle of SOLID designing principles.

public interface IBinder
{

}

public interface IBinder<in T> : IBinder
{
    void Bind(IEnumerable<T> bounds);
}

public interface IBinderDirector<T>
{
    IBinder<T>[] DataBinders { get; }

    void Bind(IEnumerable<T> bounds);
    void BindParallel(IEnumerable<T> bounds);
    void BindOnlySelected(IEnumerable<T> bounds, IEnumerable<Type> selecteds);
    void BindAllExcept(IEnumerable<T> bounds, IEnumerable<Type> excepts);
    void BindOnlySelectedParallel(IEnumerable<T> bounds, IEnumerable<Type> selecteds);
    void BindAllExceptParallel(IEnumerable<T> bounds, IEnumerable<Type> excepts);
}

public class BinderDirector<T> : IBinderDirector<T>
{
    private readonly IBinder<T>[] _dataBinders;
    public IBinder<T>[] DataBinders => throw new NotImplementedException();

    public BinderDirector(IEnumerable<IBinder<T>> dataBinders)
    {
        _dataBinders = (dataBinders ?? Enumerable.Empty<IBinder<T>>()).ToArray();
    }

    public void Bind(IEnumerable<T> bounds)
    {
        var boundAsList = bounds.ToArray();
        foreach (var dataBinder in _dataBinders) dataBinder.Bind(boundAsList);
    }

    public void BindAllExcept(IEnumerable<T> bounds, IEnumerable<Type> excepts)
    {
        var boundArray = bounds.ToArray();
        var runnableDataBinders = _dataBinders.Where(m => excepts.Any(s => !s.IsAssignableFrom(m.GetType())));
        foreach (var dataBinder in runnableDataBinders) dataBinder.Bind(bounds);
    }

    public void BindAllExceptParallel(IEnumerable<T> bounds, IEnumerable<Type> excepts)
    {
        var boundArray = bounds.ToArray();
        var runnableDataBinders = _dataBinders.Where(m => excepts.Any(s => !s.IsAssignableFrom(m.GetType())));
        Parallel.ForEach(runnableDataBinders, (runnableDataBinder, index) => runnableDataBinder.Bind(bounds));
    }

    public void BindOnlySelected(IEnumerable<T> bounds, IEnumerable<Type> selecteds)
    {
        var boundArray = bounds.ToArray();
        var runnableDataBinders = _dataBinders.Where(m => selecteds.Any(s => s.IsAssignableFrom(m.GetType())));
        foreach (var dataBinder in runnableDataBinders) dataBinder.Bind(bounds);
    }

    public void BindOnlySelectedParallel(IEnumerable<T> bounds, IEnumerable<Type> selecteds)
    {
        var boundArray = bounds.ToArray();
        var runnableDataBinders = _dataBinders.Where(m => selecteds.Any(s => s.IsAssignableFrom(m.GetType())));
        Parallel.ForEach(runnableDataBinders, (runnableDataBinder, index) => runnableDataBinder.Bind(bounds));
    }

    public void BindParallel(IEnumerable<T> bounds)
    {
        var boundArray = bounds.ToArray();
        Parallel.ForEach(_dataBinders, dataBinder => dataBinder.Bind(boundArray));
    }
}

Underneath you will find an example of concrete implementation. The thing which is interesant, is that the BinderDirector is a pure interpretation of the Interface Segregation Principle :

public interface IWithBindPropertiesA
{
    string IdentifierA { get; }
    string ReturnedPropertyValueA { set; }
}

public interface IWithBindPropertiesB
{
    string IdentifierB { get; }
    string ReturnedPropertyValueB { set; }
}

public class ConcreteImplementation : IWithBindPropertiesA, IWithBindPropertiesB
{
    public new string IdentifierA { get; set; }

    public new string ReturnedPropertyValueA { get; set; }

    public new string IdentifierB { get; set; }

    public new string ReturnedPropertyValueB { get; set; }
}

public class BindPropertiesABinder : IBinder<IWithBindPropertiesA>
{
    public void Bind(IEnumerable<IWithBindPropertiesA> bounds)
    {
        foreach (var bound in bounds)
        {
            bound.ReturnedPropertyValueA = bound.IdentifierA == "A" ? "A" : "unknown"; // In fact you can do what you want
        }
    }
}

public class BindPropertiesBBinder : IBinder<IWithBindPropertiesB>
{
    public void Bind(IEnumerable<IWithBindPropertiesB> bounds)
    {
        foreach (var bound in bounds)
        {
            bound.ReturnedPropertyValueB = bound.IdentifierB == "B" ? "B" : "unknown"; // In fact you can do what you want
        }
    }
}

public static class Program
{
    public static void Main(string[] argc)
    {
        var binderDirector = new BinderDirector<ConcreteImplementation>(new IBinder<ConcreteImplementation>[] {
            new BindPropertiesABinder(),
            new BindPropertiesBBinder()
        });
    }
}