Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Easy (and with three different GOF design patterns).</p> <p>Since we can't do anything with the components, we'll have to use the bridge pattern. </p> <p>Let's define handlers:</p> <pre><code>public interface IHandlerOf&lt;T&gt; where T : Component { void DoWork(T component); } </code></pre> <p>So now we can create a handler type for each component type that we want to handle. A DB component handler would look like this:</p> <pre><code>public class DbComponentHandler : IHandlerOf&lt;DbComponent&gt; { public void DoWork(DbComponent component) { // do db specific information here } } </code></pre> <p>But since we don't really want to keep track of all handlers we'll want to create a class that does it for us. We ultimately want to invoke the code just as in your example: </p> <pre><code>foreach (Component component in ComponentList) { handler.DoWork(component); } </code></pre> <p>But let's make it a bit cooler:</p> <pre><code>//maps handlers to components var service = new ComponentService(); // register all handlers in the current assembly service.Register(Assembly.GetExecutingAssembly()); // fake a component var dbComponent = new DbComponent(); // the cool part, the invoker doesn't have to know // about the handlers = facade pattern service.Invoke(dbComponent); </code></pre> <p>The service with makes it possible looks like this:</p> <pre><code>public class ComponentService { private readonly Dictionary&lt;Type, IHandlerInvoker&gt; _handlers = new Dictionary&lt;Type, IHandlerInvoker&gt;(); public void Register(Assembly assembly) { foreach (var type in assembly.GetTypes()) { if (type.IsInterface) continue; foreach (var interfaceType in type.GetInterfaces()) { if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != typeof(IHandlerOf&lt;&gt;)) continue; var componentType = interfaceType.GetGenericArguments()[0]; var instance = Activator.CreateInstance(type); var method = instance.GetType().GetMethod("DoWork", new[] { componentType }); _handlers[componentType] = new ReflectionInvoker(instance, method); } } } public void Register&lt;T&gt;(IHandlerOf&lt;T&gt; handler) where T : Component { _handlers[typeof (T)] = new DirectInvoker&lt;T&gt;(handler); } #region Nested type: DirectInvoker private class DirectInvoker&lt;T&gt; : IHandlerInvoker where T : Component { private readonly IHandlerOf&lt;T&gt; _handler; public DirectInvoker(IHandlerOf&lt;T&gt; handler) { _handler = handler; } #region IHandlerInvoker Members public void Invoke(Component component) { _handler.DoWork((T) component); } #endregion } #endregion #region Nested type: IHandlerInvoker private interface IHandlerInvoker { void Invoke(Component component); } #endregion #region Nested type: ReflectionInvoker private class ReflectionInvoker : IHandlerInvoker { private readonly object _instance; private readonly MethodInfo _method; public ReflectionInvoker(object instance, MethodInfo method) { _instance = instance; _method = method; } #region IHandlerInvoker Members public void Invoke(Component component) { _method.Invoke(_instance, new object[] {component}); } #endregion } #endregion public void Invoke(Component component) { IHandlerInvoker invoker; if (!_handlers.TryGetValue(component.GetType(), out invoker)) throw new NotSupportedException("Failed to find a handler for " + component.GetType()); invoker.Invoke(component); } } </code></pre> <p>Do note that the interface (<code>IHandlerOf&lt;T&gt;</code>) is generic which means that we can't store it directly in a Dictionary. Hence we use the Adapter pattern to store all handlers.</p> <hr> <p>Full example:</p> <pre><code>public interface IHandlerOf&lt;in T&gt; where T : Component { void DoWork(T component); } public class ComponentService { private readonly Dictionary&lt;Type, IHandlerInvoker&gt; _handlers = new Dictionary&lt;Type, IHandlerInvoker&gt;(); public void Register(Assembly assembly) { foreach (var type in assembly.GetTypes()) { if (type.IsInterface) continue; foreach (var interfaceType in type.GetInterfaces()) { if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != typeof(IHandlerOf&lt;&gt;)) continue; var componentType = interfaceType.GetGenericArguments()[0]; var instance = Activator.CreateInstance(type); var method = instance.GetType().GetMethod("DoWork", new[] { componentType }); _handlers[componentType] = new ReflectionInvoker(instance, method); } } } public void Register&lt;T&gt;(IHandlerOf&lt;T&gt; handler) where T : Component { _handlers[typeof (T)] = new DirectInvoker&lt;T&gt;(handler); } #region Nested type: DirectInvoker private class DirectInvoker&lt;T&gt; : IHandlerInvoker where T : Component { private readonly IHandlerOf&lt;T&gt; _handler; public DirectInvoker(IHandlerOf&lt;T&gt; handler) { _handler = handler; } #region IHandlerInvoker Members public void Invoke(Component component) { _handler.DoWork((T) component); } #endregion } #endregion #region Nested type: IHandlerInvoker private interface IHandlerInvoker { void Invoke(Component component); } #endregion #region Nested type: ReflectionInvoker private class ReflectionInvoker : IHandlerInvoker { private readonly object _instance; private readonly MethodInfo _method; public ReflectionInvoker(object instance, MethodInfo method) { _instance = instance; _method = method; } #region IHandlerInvoker Members public void Invoke(Component component) { _method.Invoke(_instance, new object[] {component}); } #endregion } #endregion public void Invoke(Component component) { IHandlerInvoker invoker; if (!_handlers.TryGetValue(component.GetType(), out invoker)) throw new NotSupportedException("Failed to find a handler for " + component.GetType()); invoker.Invoke(component); } } public class DbComponent : Component { } public class DbComponentHandler : IHandlerOf&lt;DbComponent&gt; { public void DoWork(DbComponent component) { // do db specific information here Console.WriteLine("some work done!"); } } internal class Program { private static void Main(string[] args) { var service = new ComponentService(); service.Register(Assembly.GetExecutingAssembly()); var dbComponent = new DbComponent(); service.Invoke(dbComponent); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload