Async variant of Messenger

Jan 23, 2011 at 10:05 AM

what about creating asynchronous variant of Messenger, having

executeAction.ExecuteWithObject(message);

changed to

Task.Factory.StartNew (executeAction.ExecuteWithObject, message, TaskCreationOptions.AttachedToParent);

i created one (source below) by inheriting stock Messenger, but forced to change sources to make some members protected instead of private:

private struct WeakActionAndToken => protected struct WeakActionAndToken
private static void SendToList<TMessage>() => protected virtual void SendToList<TMessage> ()
private void SendToTargetOrType<TMessage>() => protected void SendToTargetOrType<TMessage>()

what i need is either ready to use asynchronous Messenger, or some way to inherit and change behavior of standard Messenger. also very desirable is to have CancellationToken, TaskCreationOptions and TaskScheduler, stored in messenger for launching tasks either on by-subscriber basis or globally (specified in constructor like TaskFactory does)

full source of my sample asynchronous Messenger (method SendToList<TMessage> is equal to standard Messenger except last line):

using System;
using System.Linq;
using System.Threading.Tasks;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Helpers;

namespace BusinessClassLibrary
{
	public class TaskMessenger : Messenger
	{
		private static Lazy<TaskMessenger> DefaultInstance = new Lazy<TaskMessenger> ();
		public static new TaskMessenger Default { get { return DefaultInstance.Value; } }

		public TaskMessenger () : base () { }

		public Task SendTask<TMessage> (TMessage message)
		{
			return Task.Factory.StartNew (SendMessage<TMessage>, message);
		}
		public Task SendTask<TMessage, TTarget> (TMessage message)
		{
			return Task.Factory.StartNew (SendMessageAndType<TMessage, TTarget>, message);
		}
		public Task SendTask<TMessage> (TMessage message, object token)
		{
			return Task.Factory.StartNew (SendMessageAndToken<TMessage>, Tuple.Create<TMessage, object> (message, token));
		}

		private void SendMessage<TMessage> (object message)
		{
			SendToTargetOrType ((TMessage)message, null, null);
		}

		private void SendMessageAndType<TMessage, TTarget> (object message)
		{
			SendToTargetOrType ((TMessage)message, typeof (TTarget), null);
		}

		private void SendMessageAndToken<TMessage> (object tupleObj)
		{
			var tuple = (Tuple<TMessage, object>)tupleObj;
			SendToTargetOrType (tuple.Item1, null, tuple.Item2);
		}

		protected override void SendToList<TMessage> (
			TMessage message,
			System.Collections.Generic.IEnumerable<WeakActionAndToken> list,
			Type messageTargetType,
			object token)
		{
			if (list != null)
			{
				// Clone to protect from people registering in a "receive message" method
				// Bug correction Messaging BL0004.007
				var listClone = list.Take (list.Count ()).ToList ();

				foreach (var item in listClone)
				{
					var executeAction = item.Action as IExecuteWithObject;

					if (executeAction != null
						&& item.Action.IsAlive
						&& item.Action.Target != null
						&& (messageTargetType == null
							|| item.Action.Target.GetType () == messageTargetType
							|| messageTargetType.IsAssignableFrom (item.Action.Target.GetType ()))
						&& ((item.Token == null && token == null)
							|| item.Token != null && item.Token.Equals (token)))
					{
						Task.Factory.StartNew (executeAction.ExecuteWithObject, message, TaskCreationOptions.AttachedToParent);
					}
				}
			}
		}
	}
}