1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public interface IBehaviorExecutor
  {
    void ExecuteBehaviorsFor(object viewModel);
  }

  public class BehaviorExecutor : IBehaviorExecutor
  {
        public BehaviorExecutor(IBehaviorRegistry behaviorRegistry, IContext context)
        {
            BehaviorRegistry = behaviorRegistry;
            Context = context;
        }

        protected IBehaviorRegistry BehaviorRegistry { get; set; }
        protected IContext Context { get; set; }

        public void ExecuteBehaviorsFor(object viewModel)
        {
            foreach (var behavior in BehaviorRegistry.BehaviorsFor(viewModel.GetType()))
            {
                var toApply = Context.Resolve(behavior);
                behavior.InvokeMember("Apply", BindingFlags.InvokeMethod, null, toApply, new[] {viewModel});
            }
        }
    }

  public interface IBehaviorRegistry
  {
    void DiscoverBehaviors();
    IEnumerable<Type> BehaviorsFor(Type viewModel);
  }

  public class BehaviorRegistry : IBehaviorRegistry
  {
        private readonly IList<TypePair> _behaviorMap = new List<TypePair>();

        public BehaviorRegistry()
        {
            DiscoverBehaviors();
        }

        public void DiscoverBehaviors()
        {
            if (_behaviorMap.Any())
                return;

            var behaviors = ReflectionHelper.GetAllReachableTypes()
                .ThatImplementInterface<IBehavior>()
                .ThatAreNotInterfaces();

            foreach (var behavior in behaviors)
            {
                var typeFor = behavior.GetInterfaces().First().GetGenericArguments().FirstOrDefault();

                if (typeFor == null)
                    throw new InvalidOperationException
                        (string.Format("Behavior {0} must derive directly from IBehavior<T>", behavior));

                _behaviorMap.Add(new TypePair(typeFor, behavior));
            }
        }


        public IEnumerable<Type> BehaviorsFor(Type viewModel)
        {
            return  _behaviorMap.Where(b => b.Model.IsAssignableFrom(viewModel))
              .OrderByDescending(p => ReflectionHelper.InheritanceDistance(p.Model, viewModel))
              .Select(p => p.Behavior)
              .Distinct()
              .ToArray();
        }

        #region Nested type: TypePair

        private class TypePair
        {
            public TypePair(Type model, Type behavior)
            {
                Model = model;
                Behavior = behavior;
            }

            public Type Model { get; set; }
            public Type Behavior { get; set; }
        }

        #endregion
    }