2
\$\begingroup\$

Sorry for being a little abstract but I have attempted to concoct something simple but it seems to spiral out of control. So I was thinking maybe I am taking the wrong approach.

Here's what I am trying to do:

When I get a message it gets de-serialized into its own class. I would like to use a strategy pattern to choose a message processor that would be able to process the message

How would you do it?

Here are my attempts at this that got very convoluted the closer I got to the goal. I mean, it works but I would have thought it would be cleaner than this so just thinking I must be going about this wrong:

  1. https://stackoverflow.com/questions/35801156/cant-seem-to-get-generic-covariance-contravariance-to-work

  2. https://stackoverflow.com/questions/35784981/why-is-thisinterfacet-not-of-type-interfacet-using-an-is-keyword-comparison

  3. https://stackoverflow.com/questions/35777762/cant-convert-from-abstractgeneric-to-concreteabstractconcretegeneric

Here's my code (but I am looking for ideas to avoid the MessageProcessorWrapper). How would you re-write it?:

public interface IBaseMessage { 
   public int ID() { get; set; }
}

public interface IMessageProcessor<in T> where T : IBaseMessage {
            void Process(T msg);
        }

public class RRMessage : IBaseMessage {
          public string Text {get; set;}
          public DateTime RRProcessDate {get; set; }
        }

public class BaseMessageProcessor {
         public int MessageProcID{ get; set; }
         public BaseMessageProcessor(int mid) {
            MessageProcID = mid;
         }
      }

public class RRMessageProcessor : BaseMessageProcessor, IMessageProcessor<RRMessage> {
            public void Process(RRMessage msg) {
                WriteToDatabase(msg);
                UpdateInternalTrackers(msg);
                Console.WriteLine("Processed RRMessage");
            }
        }

public class ProcessorWrapper<T> : IMessageProcessor<IBaseMessage> {
    private readonly IMessageProcessor<T> inner;
    public ProcessorWrapper(IMessageProcessor<T> inner) { this.inner = inner; }

    public void Process(IBaseMessage msg)
    {
        if(msg is T) { inner.Process((T)msg); }
        else throw new ArgumentException("Invalid message type");
    }
}

[TestFixture]
public class MyTestFixture {
    public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>();


    [Test]
    public void Test1() {
         var msgProcessor = new RRMessageProcessor();
         MessageProcessors.Add(typeof(RRMessage), new ProcessorWrapper<RRMessage>(msgProcessor);
         }
   }
\$\endgroup\$
  • \$\begingroup\$ Thank you and welcome to Code Review! I hope you get some great answers. \$\endgroup\$ – Phrancis Mar 7 '16 at 15:43
1
\$\begingroup\$

Not the answer you're looking for, but this bit of code casts msg twice: if(msg is T) { inner.Process((T)msg); }. You can cast it once by using as, e.g. var m = msg as T; if (m != null) inner.Process(m); Also if you're actually writing the if bit on one line (as I love to do for one-liners) then I don't see the point of using curly braces on that line, though I guess that's just a style issue. You didn't use it for the else part after all.

And I'm sure in "real life" you won't have a test called "Test1", so I won't say anything about that...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.