The current implementation is pretty much aligns with a simple Strategy Design Pattern. There are multiple steps to be executed and these will be invoked provided by the following interface:
public interface ICommandStep
{
void Execute(CommandParameters cParams);
string StepName { get; }
}
Example implementor:
public class Step1 : ICommandStep {
public string StepName => "Initial Step";
public void Execute(CommandParameters cParams) {
// instructions
}
}
By now there many different classes implementing this interface, and I want to ensure all of them will have a pre and post step to execution. For example log state, params, StepName start and end.
How could I introduce a way to have protected virtual void PreExecute and protected virtual void PostExecute methods with common (overridable) logic and to make sure the method will always be invoked in this order:
1. PreExecute
2. Execute
3. PostExecute
Preferably without changing the Execute method in the implementor classes.
Introducing abstract class is possible.
You can declare base class and define overridable methods in needed order:
public interface ICommandStep
{
void Execute(CommandParameters cParams);
string StepName { get; }
}
public abstract class CommandBase : ICommandStep
{
public void Execute(CommandParameters cParams)
{
PreExecute();
ExecuteInternal(cParams);
PostExecute();
}
protected virtual void PostExecute()
{
}
protected virtual void ExecuteInternal(CommandParameters cParams)
{
}
protected virtual void PreExecute()
{
}
public abstract string StepName { get; }
}
public class Step1 : CommandBase
{
public override string StepName => "Initial Step";
protected override void ExecuteInternal(object cParams)
{
// instructions
}
}
Adding new methods to the interface will necessarily mean breaking the existing implementations. If implementation is optional then you should use an abstract class instead of an interface.
An alternative exists by adding a new interface and adding a runtime type-check in an extension method, like so:
public interface ICommandStep
{
void Execute(CommandParameters cParams);
string StepName { get; }
}
public interface ICommandStep2 : ICommandStep
{
void PreExecute()
void PostExecute()
}
public static class Extensions
{
public static void Execute2(this ICommandStep step, CommandParameters cParams)
{
if( step is ICommandStep2 step2 )
{
step2.PreExecute();
step2.Execute( cParams );
step2.PostExecute();
}
else
{
step2.Execute( cParams );
}
}
}
Usage:
ICommandStep[] steps = ...
foreach( ICommandStep step in steps )
{
step.Execute2( cmdParams );
}
I can think of 2 solutions:
Template Method pattern as proposed by Backs.
Decorator Pattern together with factory. Decorator pattern is great when you want to execute some code before/after call to other object. Factory is to ensure that each created object will be decorated.
Example implementation of 2.:
using System;
namespace ConsoleApplication6
{
/// <summary>
/// This is the component in Decorator Pattern
/// </summary>
public interface ICommandStep
{
void Execute(String cParams);
string StepName { get; }
}
/// <summary>
/// This is the concrete component in Decorator Pattern
/// </summary>
public class ConcreteStep1 : ICommandStep
{
public string StepName
{
get
{
return "1";
}
}
public void Execute(string cParams)
{
Console.WriteLine($"STEP {StepName}: EXECUTE");
}
}
/// <summary>
/// This is the decorator in Decorator Pattern
/// </summary>
public abstract class StepDecorator : ICommandStep
{
protected ICommandStep _commandStep;
public abstract string StepName
{
get;
}
public StepDecorator(ICommandStep commandStep)
{
this._commandStep = commandStep;
}
public abstract void Execute(string cParams);
}
/// <summary>
/// This is the concrete decorator in Decorator Pattern
/// </summary>
public class ConcreteStepDecorator : StepDecorator
{
public ConcreteStepDecorator(ICommandStep commandStep) : base(commandStep) { }
public override string StepName
{
get
{
return _commandStep.StepName;
}
}
public override void Execute(string cParams)
{
// You can do whatever you want before / after execution of command
Console.WriteLine($"STEP {_commandStep.StepName}: PRE EXECUTE");
_commandStep.Execute(cParams);
Console.WriteLine($"STEP {_commandStep.StepName}: POST EXECUTE");
}
}
/// <summary>
/// This is a Simple Factory. You encapsulate here creation of ICommandStep, so that it will always be decorated
/// </summary>
public class SimpleStepFactory
{
public ICommandStep createStep()
{
return new ConcreteStepDecorator(new ConcreteStep1());
}
}
class Program
{
static void Main(string[] args)
{
var step = new SimpleStepFactory().createStep();
step.Execute("params");
Console.ReadLine();
}
}
}
This solution has couple of advantages:
You can wrap your steps with many decorators, i.e. you can wrap step in decorator that shows it's name and wrap these two in another decorator that shows the parameters
You don't have to modify your steps, because all the extra work is handled by decorators
I've got some methods in one class that return values of to,from,message and im trying to use these in the other class that has the default display message.
I can't seem to use the string values that I get from the methods in class 1 in class 2.
I have tried declaring the string values public but got overloaded with errors none of which really said why the error was happening.
public class ChristmasCard
{
public static void Main()
{
string toWhom = To();
string fromWhom = From();
double decorate = ChooseDecoration();
string message = AddMessage();
DoPromt(message);
DisplayMessage(decorate);
Console.ReadLine();
}
public class ChristmasCardTesting : ChristmasCard
{
public static void SantaA()
{
Console.WriteLine(ChristmasCard.toWhom);
Console.WriteLine(ChristmasCard.Message1);
Console.WriteLine(ChristmasCard.Message2);
Console.WriteLine(ChristmasCard.Message3);
Console.WriteLine(ChristmasCard.fromWhom);
Console.ReadLine();
I guess inheritance is not what you want here. You want to use an instance of your object instead.
First you want to create an instance of your ChristmasCard.
That instance should hold Properties/Fields of the values you like to hold in the RAM.
Then you want to create an instance of your ChristmasCardTesting and call the "testmethod" while giving the christmas card as parameter.
And that code could be executed in your Program.
I guess what you want to achieve should more like the following:
public class Program {
public static void Main(string[] args) {
ChristmasCard card = new ChristmasCard();
ChristmasCardController controller = new ChristmasCardController();
controller.SomeMethod(card);
WriteToConsole(card);
}
public static void WriteToConsole(ChristmasCard card) {
Console.WriteLine(card.ToWhom);
Console.WriteLine(card.Message);
Console.WriteLine(card.FromWhom);
Console.ReadLine();
}
}
/// <summary>
/// Pure data class does not needs methods!
/// </summary>
public class ChristmasCard {
public string ToWhom { get; set; }
public string FromWhom { get; set; }
public double Decorate { get; set; }
public string Message { get; set; }
}
/// <summary>
/// Controller for the dataClass
/// </summary>
public class ChristmasCardController {
public void SomeMethod(ChristmasCard card) {
card.ToWhom = To();
card.FromWhom = From();
card.Decorate = ChooseDecoration();
card.Message = AddMessage();
DoPromt(card);
DisplayMessage(card.Decorate);
}
private void DisplayMessage(double cardDecorate) {
//Write your message to the console
}
private void DoPromt(ChristmasCard card) {
//Do some ConsoleRead in here
}
private string AddMessage() {
throw new NotImplementedException();
}
private double ChooseDecoration() {
throw new NotImplementedException();
}
private string From() {
throw new NotImplementedException();
}
private string To() {
throw new NotImplementedException();
}
}
Edit:
If that is totally not what you want, please explain what you are trying to achieve and i'm 100% sure i'll find the answer.
Edit2
All methods from that Controller class could also be in the Program class.
Note these would have to be static if you move these methods. I hope this snipped makes it clear how to solve the problem.
I have Singleton class that get's data from web. And i need to pass those data to classes FirstDerived and SecondDerived. In this case is my class Singleton anti-pattern? Is it normal to use Aggregation relationship between DataSocket and FirstDerived, SecondDerived. Maybe it exist better object oriented solution?
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
public class TestViewModel
{
public ObservableCollection<Base> Items { get; set; }
public TestViewModel()
{
DataSocket.Instance.SendDataAsync();
Items = new ObservableCollection<Base>();
Items.Add(new FirstDerived(1, DataSocket.Instance));
Items.Add(new SecondDerived(2, DataSocket.Instance));
}
}
public abstract class Base
{
}
public class FirstDerived : Base, IDisposable
{
public FirstDerived(int id, DataSocket socket)
{
socket.Client += ProcessDataFromSocket;
}
public void ProcessDataFromSocket(string arg)
{
Console.WriteLine("First Derived getting data: {0}", arg.ToString());
}
public void Dispose()
{
throw new NotImplementedException();
}
}
public class SecondDerived : Base, IDisposable
{
public SecondDerived(int id, DataSocket socket)
{
DataSocket.Instance.Client += ProcessDataFromSocket;
}
public void ProcessDataFromSocket(string arg)
{
Console.WriteLine("Second Derived getting data: {0}", arg.ToString());
}
public void Dispose()
{
throw new NotImplementedException();
}
}
public sealed class DataSocket
{
private static DataSocket instance;
public delegate void Messages(string info);
public event Messages Client;
private DataSocket()
{
}
public void SendDataAsync()
{
Action Send = new Action(SendData);
IAsyncResult result = Send.BeginInvoke(null,null);
}
public void SendData()
{
while(true)
{
if (Client != null)
{
System.Threading.Thread.Sleep(3000);
Client("Test");
}
}
}
public static DataSocket Instance
{
get
{
if (instance==null)
{
instance = new DataSocket();
}
return instance;
}
}
}
}
To me it looks like DataSocket is the class that deals with networking, so any code to interact with the network should go there. Don't pass it into a constructor.
Rather, do something more like this sequence;
DataSocket.Instance.SendDataAsync();
Items = new ObservableCollection<Base>();
var data1 = await DataSocket.ReadData();
var data2 = await DataSocket.ReadData();
Items.Add(new FirstDerived(1, data1));
Items.Add(new SecondDerived(2, data2));
This way, your classes don't take a dependency on a global, constantly-changing object.
You might also want to consider some kind of lock statement to make sure that different parts of the code -- say, many different simultaneous web requests -- can't interfere with each other.
Suppose you had such code:
public Base
{
abstract void Register();
}
public Registrator1: Base
{
override void Register()
{
//uses the current state of the object to populate the UI captions
}
}
public Registrator2: Base
{
override void Register()
{
//uses the current state of the object to populate the UI captions
}
}
But When you receive a new business rule asking you to write Registrator3 which actually registers based on some parameter and you change your code base to the next:
public Base
{
abstract void Register(externalParam);
}
public Registrator1: Base
{
override void Register(externalParam)
{
//uses the current state of the object to populate theUI
}
}
public Registrator2: Base
{
override void Register(externalParam)
{
//uses the current state of the object to populate the UI
}
}
public Registrator3: Base
{
override void Register(externalParam)
{
//uses a DDD - service passed in the params to populate the UI
}
}
But Registrator1 and Registrator2 do not need that param and the code becomes smelly. What are the ways to re-write this code?
You could use an object as a parameter here; which is commonly used in scenarios where the number of parameters can vary depending on the call being used.
struct RegistrationInfo
{
public static readonly RegistrationInfo Empty = new RegistrationInfo();
public string Username;
public string CustomerName;
public string Validity;
}
abstract class Base
{
public abstract void Register(RegistrationInfo info);
// If you want to retain the paramaterless call:
public void Register()
{
Register(RegistrationInfo.Empty);
}
}
class Registrar1 : Base
{
public override void Register(RegistrationInfo info)
{
if (info.Username == null) throw new ArgumentNullException("info.Username");
}
}
class Registrar2 : Base
{
public override void Register(RegistrationInfo info)
{
if (info.CustomerName == null) throw new ArgumentNullException("info.CustomerName");
}
}
This has the advantage that you don't need to change method parameters (which is breaking interface) each time a parameter is added. The usage also becomes somewhat self-documenting:
var r = new Registrar1();
r.Register(new RegistrationInfo(){ Username = "JimJoe" });
r.Register(RegistrationInfo.Empty);
It's like air freshener for this type of code smell, while it's still smelly; you can make it smell nicer.
Finally you can make the call-site cleaner by making it a params argument (this has a small amount of overhead); in all honesty though it is more smelly because it's a language hack. Finally you could improve it with generics:
class RegistrationInfo
{
}
class RegistrationInfo1 : RegistrationInfo
{
public string Arg;
}
class RegistrationInfo2 : RegistrationInfo
{
public int Arg;
}
interface IBase<in TRegistration>
where TRegistration : RegistrationInfo
{
void Register(TRegistration registration);
}
class Base : IBase<RegistrationInfo>
{
public void Register(RegistrationInfo registration)
{
}
}
class Registrar1 : IBase<RegistrationInfo1>
{
public void Register(RegistrationInfo1 arg)
{
}
}
class Registrar2 : IBase<RegistrationInfo2>
{
public void Register(RegistrationInfo2 arg)
{
}
}
Is it not possible to contain the logic for externalParam in Registrator3?
In other words, Registrator3 uses the param, then calls the unmodified parameterless base?
A lot really depends on where the logic belongs. If it is something intrinsic to the base, then put it in the base, and either overload the Register() function or supply a default value for the param so that sub classes don't need to provide it.
Assuming you want to reuse the registration logic from the base class, you could update the code as follows:
public class Base
{
public virtual void Register(object externalParam)
{
// base registration logic goes here
}
}
public class Registrator1: Base
{
public override void Register(object externalParam)
{
base.Register(null);
// custom registration logic goes here
}
}
public class Registrator2: Base
{
public override void Register(object externalParam)
{
base.Register(null);
// custom registration logic goes here
}
}
public class Registrator3: Base
{
public override void Register(object externalParam)
{
base.Register(externalParam);
// custom registration logic goes here
}
}
HTH,
Cosmin
EDIT: Updated code to compile.
I've created a new class called Actor which processes messages passed to it.
The problem I am running into is figuring out what is the most elegant way to pass related but different messages to the Actor. My first idea is to use inheritance but it seems so bloated but it is strongly types which is a definite requirement.
Have any ideas?
Example
private abstract class QueueMessage { }
private class ClearMessage : QueueMessage
{
public static readonly ClearMessage Instance = new ClearMessage();
private ClearMessage() { }
}
private class TryDequeueMessage : QueueMessage
{
public static readonly TryDequeueMessage Instance = new TryDequeueMessage();
private TryDequeueMessage() { }
}
private class EnqueueMessage : QueueMessage
{
public TValue Item { get; private set; }
private EnqueueMessage(TValue item)
{
Item = item;
}
}
Actor Class
/// <summary>Represents a callback method to be executed by an Actor.</summary>
/// <typeparam name="TReply">The type of reply.</typeparam>
/// <param name="reply">The reply made by the actor.</param>
public delegate void ActorReplyCallback<TReply>(TReply reply);
/// <summary>Represents an Actor which receives and processes messages in concurrent applications.</summary>
/// <typeparam name="TMessage">The type of message this actor accepts.</typeparam>
/// <typeparam name="TReply">The type of reply made by this actor.</typeparam>
public abstract class Actor<TMessage, TReply> : IDisposable
{
/// <summary>The default total number of threads to process messages.</summary>
private const Int32 DefaultThreadCount = 1;
/// <summary>Used to serialize access to the message queue.</summary>
private readonly Locker Locker;
/// <summary>Stores the messages until they can be processed.</summary>
private readonly System.Collections.Generic.Queue<Message> MessageQueue;
/// <summary>Signals the actor thread to process a new message.</summary>
private readonly ManualResetEvent PostEvent;
/// <summary>This tells the actor thread to stop reading from the queue.</summary>
private readonly ManualResetEvent DisposeEvent;
/// <summary>Processes the messages posted to the actor.</summary>
private readonly List<Thread> ActorThreads;
/// <summary>Initializes a new instance of the Genex.Concurrency<TRequest, TResponse> class.</summary>
public Actor() : this(DefaultThreadCount) { }
/// <summary>Initializes a new instance of the Genex.Concurrency<TRequest, TResponse> class.</summary>
/// <param name="thread_count"></param>
public Actor(Int32 thread_count)
{
if (thread_count < 1) throw new ArgumentOutOfRangeException("thread_count", thread_count, "Must be 1 or greater.");
Locker = new Locker();
MessageQueue = new System.Collections.Generic.Queue<Message>();
EnqueueEvent = new ManualResetEvent(true);
PostEvent = new ManualResetEvent(false);
DisposeEvent = new ManualResetEvent(true);
ActorThreads = new List<Thread>();
for (Int32 i = 0; i < thread_count; i++)
{
var thread = new Thread(ProcessMessages);
thread.IsBackground = true;
thread.Start();
ActorThreads.Add(thread);
}
}
/// <summary>Posts a message and waits for the reply.</summary>
/// <param name="value">The message to post to the actor.</param>
/// <returns>The reply from the actor.</returns>
public TReply PostWithReply(TMessage message)
{
using (var wrapper = new Message(message))
{
lock (Locker) MessageQueue.Enqueue(wrapper);
PostEvent.Set();
wrapper.Channel.CompleteEvent.WaitOne();
return wrapper.Channel.Value;
}
}
/// <summary>Posts a message to the actor and executes the callback when the reply is received.</summary>
/// <param name="value">The message to post to the actor.</param>
/// <param name="callback">The callback that will be invoked once the replay is received.</param>
public void PostWithAsyncReply(TMessage value, ActorReplyCallback<TReply> callback)
{
if (callback == null) throw new ArgumentNullException("callback");
ThreadPool.QueueUserWorkItem(state => callback(PostWithReply(value)));
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
if (DisposeEvent.WaitOne(10))
{
DisposeEvent.Reset();
PostEvent.Set();
foreach (var thread in ActorThreads)
{
thread.Join();
}
((IDisposable)PostEvent).Dispose();
((IDisposable)DisposeEvent).Dispose();
}
}
/// <summary>Processes a message posted to the actor.</summary>
/// <param name="message">The message to be processed.</param>
protected abstract void ProcessMessage(Message message);
/// <summary>Dequeues the messages passes them to ProcessMessage.</summary>
private void ProcessMessages()
{
while (PostEvent.WaitOne() && DisposeEvent.WaitOne(10))
{
var message = (Message)null;
while (true)
{
lock (Locker)
{
message = MessageQueue.Count > 0 ?
MessageQueue.Dequeue() :
null;
if (message == null)
{
PostEvent.Reset();
break;
}
}
try
{
ProcessMessage(message);
}
catch
{
}
}
}
}
/// <summary>Represents a message that is passed to an actor.</summary>
protected class Message : IDisposable
{
/// <summary>The actual value of this message.</summary>
public TMessage Value { get; private set; }
/// <summary>The channel used to give a reply to this message.</summary>
public Channel Channel { get; private set; }
/// <summary>Initializes a new instance of Genex.Concurrency.Message class.</summary>
/// <param name="value">The actual value of the message.</param>
public Message(TMessage value)
{
Value = value;
Channel = new Channel();
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
Channel.Dispose();
}
}
/// <summary>Represents a channel used by an actor to reply to a message.</summary>
protected class Channel : IDisposable
{
/// <summary>The value of the reply.</summary>
public TReply Value { get; private set; }
/// <summary>Signifies that the message has been replied to.</summary>
public ManualResetEvent CompleteEvent { get; private set; }
/// <summary>Initializes a new instance of Genex.Concurrency.Channel class.</summary>
public Channel()
{
CompleteEvent = new ManualResetEvent(false);
}
/// <summary>Reply to the message received.</summary>
/// <param name="value">The value of the reply.</param>
public void Reply(TReply value)
{
Value = value;
CompleteEvent.Set();
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
((IDisposable)CompleteEvent).Dispose();
}
}
}
Steve Gilham summarized how the compiler actually handles discriminated unions. For your own code, you could consider a simplified version of that. Given the following F#:
type QueueMessage<T> = ClearMessage | TryDequeueMessage | EnqueueMessage of T
Here's one way to emulate it in C#:
public enum MessageType { ClearMessage, TryDequeueMessage, EnqueueMessage }
public abstract class QueueMessage<T>
{
// prevents unwanted subclassing
private QueueMessage() { }
public abstract MessageType MessageType { get; }
/// <summary>
/// Only applies to EnqueueMessages
/// </summary>
public abstract T Item { get; }
public static QueueMessage<T> MakeClearMessage() { return new ClearMessage(); }
public static QueueMessage<T> MakeTryDequeueMessage() { return new TryDequeueMessage(); }
public static QueueMessage<T> MakeEnqueueMessage(T item) { return new EnqueueMessage(item); }
private sealed class ClearMessage : QueueMessage<T>
{
public ClearMessage() { }
public override MessageType MessageType
{
get { return MessageType.ClearMessage; }
}
/// <summary>
/// Not implemented by this subclass
/// </summary>
public override T Item
{
get { throw new NotImplementedException(); }
}
}
private sealed class TryDequeueMessage : QueueMessage<T>
{
public TryDequeueMessage() { }
public override MessageType MessageType
{
get { return MessageType.TryDequeueMessage; }
}
/// <summary>
/// Not implemented by this subclass
/// </summary>
public override T Item
{
get { throw new NotImplementedException(); }
}
}
private sealed class EnqueueMessage : QueueMessage<T>
{
private T item;
public EnqueueMessage(T item) { this.item = item; }
public override MessageType MessageType
{
get { return MessageType.EnqueueMessage; }
}
/// <summary>
/// Gets the item to be enqueued
/// </summary>
public override T Item { get { return item; } }
}
}
Now, in code that is given a QueueMessage, you can switch on the MessageType property in lieu of pattern matching, and make sure that you access the Item property only on EnqueueMessages.
EDIT
Here's another alternative, based on Juliet's code. I've tried to streamline things so that it's got a more usable interface from C#, though. This is preferable to the previous version in that you can't get a MethodNotImplemented exception.
public abstract class QueueMessage<T>
{
// prevents unwanted subclassing
private QueueMessage() { }
public abstract TReturn Match<TReturn>(Func<TReturn> clearCase, Func<TReturn> tryDequeueCase, Func<T, TReturn> enqueueCase);
public static QueueMessage<T> MakeClearMessage() { return new ClearMessage(); }
public static QueueMessage<T> MakeTryDequeueMessage() { return new TryDequeueMessage(); }
public static QueueMessage<T> MakeEnqueueMessage(T item) { return new EnqueueMessage(item); }
private sealed class ClearMessage : QueueMessage<T>
{
public ClearMessage() { }
public override TReturn Match<TReturn>(Func<TReturn> clearCase, Func<TReturn> tryDequeueCase, Func<T, TReturn> enqueueCase)
{
return clearCase();
}
}
private sealed class TryDequeueMessage : QueueMessage<T>
{
public TryDequeueMessage() { }
public override TReturn Match<TReturn>(Func<TReturn> clearCase, Func<TReturn> tryDequeueCase, Func<T, TReturn> enqueueCase)
{
return tryDequeueCase();
}
}
private sealed class EnqueueMessage : QueueMessage<T>
{
private T item;
public EnqueueMessage(T item) { this.item = item; }
public override TReturn Match<TReturn>(Func<TReturn> clearCase, Func<TReturn> tryDequeueCase, Func<T, TReturn> enqueueCase)
{
return enqueueCase(item);
}
}
}
You'd use this code like this:
public class MessageUserTest
{
public void Use()
{
// your code to get a message here...
QueueMessage<string> msg = null;
// emulate pattern matching, but without constructor names
int i =
msg.Match(
clearCase: () => -1,
tryDequeueCase: () => -2,
enqueueCase: s => s.Length);
}
}
In your example code, you implement PostWithAsyncReply in terms of PostWithReply. That isn't ideal, because it means that when you call PostWithAsyncReply and the actor takes a while to handle it, there are actually two threads tied up: the one executing the actor and the one waiting for it to finish. It would be better to have the one thread executing the actor and then calling the callback in the asynchronous case. (Obviously in the synchronous case there's no avoiding the tying up of two threads).
Update:
More on the above: you construct an actor with an argument telling it how many threads to run. For simplicity suppose every actor runs with one thread (actually quite a good situation because actors can then have internal state with no locking on it, as only one thread accesses it directly).
Actor A calls actor B, waiting for a response. In order to handle the request, actor B needs to call actor C. So now A and B's only threads are waiting, and C's is the only one actually giving the CPU any work to do. So much for multi-threading! But this is what you get if you wait for answers all the time.
Okay, you could increase the number of threads you start in each actor. But you'd be starting them so they could sit around doing nothing. A stack uses up a lot of memory, and context switching can be expensive.
So it's better to send messages asynchronously, with a callback mechanism so you can pick up the finished result. The problem with your implementation is that you grab another thread from the thread pool, purely to sit around and wait. So you basically apply the workaround of increasing the number of threads. You allocate a thread to the task of never running.
It would be better to implement PostWithReply in terms of PostWithAsyncReply, i.e. the opposite way round. The asynchronous version is low-level. Building on my delegate-based example (because it involves less typing of code!):
private bool InsertCoinImpl(int value)
{
// only accept dimes/10p/whatever it is in euros
return (value == 10);
}
public void InsertCoin(int value, Action<bool> accepted)
{
Submit(() => accepted(InsertCoinImpl(value)));
}
So the private implementation returns a bool. The public asynchronous method accepts an action that will receive the return value; both the private implementation and the callback action are executed on the same thread.
Hopefully the need to wait synchronously is going to be the minority case. But when you need it, it could be supplied by a helper method, totally general purpose and not tied to any specific actor or message type:
public static T Wait<T>(Action<Action<T>> activity)
{
T result = default(T);
var finished = new EventWaitHandle(false, EventResetMode.AutoReset);
activity(r =>
{
result = r;
finished.Set();
});
finished.WaitOne();
return result;
}
So now in some other actor we can say:
bool accepted = Helpers.Wait<bool>(r => chocMachine.InsertCoin(5, r));
The type argument to Wait may be unnecessary, haven't tried compiling any of this. But Wait basically magics-up a callback for you, so you can pass it to some asynchronous method, and on the outside you just get back whatever was passed to the callback as your return value. Note that the lambda you pass to Wait still actually executes on the same thread that called Wait.
We now return you to our regular program...
As for the actual problem you asked about, you send a message to an actor to get it to do something. Delegates are helpful here. They let you effectively get the compiler to generate you a class with some data, a constructor that you don't even have to call explicitly and also a method. If you're having to write a bunch of little classes, switch to delegates.
abstract class Actor
{
Queue<Action> _messages = new Queue<Action>();
protected void Submit(Action action)
{
// take out a lock of course
_messages.Enqueue(action);
}
// also a "run" that reads and executes the
// message delegates on background threads
}
Now a specific derived actor follows this pattern:
class ChocolateMachineActor : Actor
{
private void InsertCoinImpl(int value)
{
// whatever...
}
public void InsertCoin(int value)
{
Submit(() => InsertCoinImpl(value));
}
}
So to send a message to the actor, you just call the public methods. The private Impl method does the real work. No need to write a bunch of message classes by hand.
Obviously I've left out the stuff about replying, but that can all be done with more parameters. (See update above).
Union types and pattern matching map pretty directly to the visitor pattern, I've posted about this a few times before:
What task is best done in a functional programming style?
https://stackoverflow.com/questions/1883246/none-pure-functional-code-smells/1884256#1884256
So if you want to pass messages with lots of different types, you're stuck implementing the visitor pattern.
(Warning, untested code ahead, but should give you an idea of how its done)
Let's say we have something like this:
type msg =
| Add of int
| Sub of int
| Query of ReplyChannel<int>
let rec counts = function
| [] -> (0, 0, 0)
| Add(_)::xs -> let (a, b, c) = counts xs in (a + 1, b, c)
| Sub(_)::xs -> let (a, b, c) = counts xs in (a, b + 1, c)
| Query(_)::xs -> let (a, b, c) = counts xs in (a, b, c + 1)
You end up with this bulky C# code:
interface IMsgVisitor<T>
{
T Visit(Add msg);
T Visit(Sub msg);
T Visit(Query msg);
}
abstract class Msg
{
public abstract T Accept<T>(IMsgVistor<T> visitor)
}
class Add : Msg
{
public readonly int Value;
public Add(int value) { this.Value = value; }
public override T Accept<T>(IMsgVisitor<T> visitor) { return visitor.Visit(this); }
}
class Sub : Msg
{
public readonly int Value;
public Add(int value) { this.Value = value; }
public override T Accept<T>(IMsgVisitor<T> visitor) { return visitor.Visit(this); }
}
class Query : Msg
{
public readonly ReplyChannel<int> Value;
public Add(ReplyChannel<int> value) { this.Value = value; }
public override T Accept<T>(IMsgVisitor<T> visitor) { return visitor.Visit(this); }
}
Now whenever you want to do something with the message, you need to implement a visitor:
class MsgTypeCounter : IMsgVisitor<MsgTypeCounter>
{
public readonly Tuple<int, int, int> State;
public MsgTypeCounter(Tuple<int, int, int> state) { this.State = state; }
public MsgTypeCounter Visit(Add msg)
{
Console.WriteLine("got Add of " + msg.Value);
return new MsgTypeCounter(Tuple.Create(1 + State.Item1, State.Item2, State.Item3));
}
public MsgTypeCounter Visit(Sub msg)
{
Console.WriteLine("got Sub of " + msg.Value);
return new MsgTypeCounter(Tuple.Create(State.Item1, 1 + State.Item2, State.Item3));
}
public MsgTypeCounter Visit(Query msg)
{
Console.WriteLine("got Query of " + msg.Value);
return new MsgTypeCounter(Tuple.Create(State.Item1, 1 + State.Item2, State.Item3));
}
}
Then finally you can use it like this:
var msgs = new Msg[] { new Add(1), new Add(3), new Sub(4), new ReplyChannel(null) };
var counts = msgs.Aggregate(new MsgTypeVisitor(Tuple.Create(0, 0, 0)),
(acc, x) => x.Accept(acc)).State;
Yes, its as obtuse as it seems, but that's how you pass multiple messages a class in a type-safe manner, and that's also why we don't implement unions in C# ;)
A long shot, but anyway..
I am assuming that discriminated-union is F# for ADT (Abstract Data Type). Which means the type could be one of several things.
In case there are two, you could try and put it in a simple generic class with two type parameters:
public struct DiscriminatedUnion<T1,T2>
{
public DiscriminatedUnion(T1 t1) { value = t1; }
public DiscriminatedUnion(T2 t1) { value = t2; }
public static implicit operator T1(DiscriminatedUnion<T1,T2> du) {return (T1)du.value; }
public static implicit operator T2(DiscriminatedUnion<T1,T2> du) {return (T2)du.value; }
object value;
}
To make it work for 3 or more, we need to replicate this class a number of times.
Any one has a solution for function overloading depending on the runtime type?
If you have this
type internal Either<'a, 'b> =
| Left of 'a
| Right of 'b
in F#, then the C# equivalent of the CLR generated for class Either<'a, 'b> has inner types like
internal class _Left : Either<a, b>
{
internal readonly a left1;
internal _Left(a left1);
}
each with a tag, a getter and a factory method
internal const int tag_Left = 0;
internal static Either<a, b> Left(a Left1);
internal a Left1 { get; }
plus a discriminator
internal int Tag { get; }
and a raft of methods to implement interfaces IStructuralEquatable, IComparable, IStructuralComparable
There is a compile-time checked discriminated union type at Discriminated union in C#
private class ClearMessage
{
public static readonly ClearMessage Instance = new ClearMessage();
private ClearMessage() { }
}
private class TryDequeueMessage
{
public static readonly TryDequeueMessage Instance = new TryDequeueMessage();
private TryDequeueMessage() { }
}
private class EnqueueMessage
{
public TValue Item { get; private set; }
private EnqueueMessage(TValue item) { Item = item; }
}
Using the discriminated union could be done as follows:
// New file
// Create an alias
using Message = Union<ClearMessage, TryDequeueMessage, EnqueMessage>;
int ProcessMessage(Message msg)
{
return Message.Match(
clear => 1,
dequeue => 2,
enqueue => 3);
}