How to implement IDisposable pattern for a serial connection wrapper - c#

I am designing a C# library that uses FTDI library to manage FTDI devices and their connections. I model it in three levels of operations:
1. Enumerate plugged devices;
2. Open/Close a connection to a specific device;
3. Write to the device, and receive bytes from it.
Currently I have the following classes:
public static class FtdiEnumerator
{
public static IEnumerable<FtdiDevice> Enumerate()
{
FTDI ftdi = new FTDI();
FTDI.FT_STATUS status;
uint bufferLenght = 0;
status = ftdi.GetNumberOfDevices(ref bufferLenght);
FTDI.FT_DEVICE_INFO_NODE[] result = new FTDI.FT_DEVICE_INFO_NODE[bufferLenght];
if (status != FTDI.FT_STATUS.FT_OK)
return Enumerable.Empty<FtdiDevice>();
status = ftdi.GetDeviceList(result);
if (status != FTDI.FT_STATUS.FT_OK)
return Enumerable.Empty<DispositivoFtdi>();
return result.Where(node => node != null)
.Select(node => new DispositivoFtdi(node))
.ToArray(); ;
}
}
public class FtdiDevice
{
protected FT_DEVICE_INFO_NODE _node;
protected FTDI _ftdi = new FTDI();
public string Description => _node.Description;
public string SerialNumber => _node.SerialNumber;
public FtdiDevice(FT_DEVICE_INFO_NODE node)
{
_node = node;
}
public void Open(uint baudRate = 115200)
{
FT_STATUS status = _ftdi.OpenBySerialNumber(_node.SerialNumber);
if (status != FT_STATUS.FT_OK)
throw new Exception();
status = _ftdi.SetBaudRate(baudRate);
if (status != FT_STATUS.FT_OK)
throw new Exception()
}
public void Close()
{
_ftdi.Close();
}
public void Write(byte[] bytes)
{
uint bytesReceived = 0;
_ftdi.Write(bytes, bytes.Length, ref bytesReceived);
}
}
I know about the IDisposable pattern, and I see a clear use case for it here, regarding FtdiDevice.Open() and FtdiDevice.Close() methods, but I see that usually the pattern is implemented with another, additional class. I imagine something like a FtdiConnection class, to be used like this, I think:
var device = new FtdiDevice(node);
using (FtdiConnection connection = device.Open())
{
connection.Write(bytes);
}
That would imply moving the Write(byte[] bytes) method to this FtdiConnection class.
I am not sure if I am in the right track, or how much sense my idea makes, and would appreciate any clarification.

I think what you want to do this:
public class FtdiConnection : IDisposable
{
private FtdiDevice device;
public FtdiConnection(FtdiDevice device)
{
this.device = device;
}
public void Dispose()
{
device.Close();
}
}
into your open method:
public FtdiConnection Open(uint baudRate = 115200)
{
... Open ...
return new FtdiConnection(this);
}
and use like
var device = new FtdiDevice(node);
using (FtdiConnection connection = device.Open())
{
connection.Write(bytes);
}

I found out, inspired on the discussion and previous answer, the following design answers my needs. I will add it here as an alternative to Gustavo's answer, and would be glad to know other alternatives.
The solution principle here is to have Device.Open() to return this as the disposable, thus avoiding the need for an additional Connection class:
using System;
namespace DisposableConnection
{
class Program
{
static void Main(string[] args)
{
var device = new Device();
using (device.Open())
{
device.Write();
}
Console.ReadKey();
}
}
public class Device : IDisposable
{
public Device()
{
}
public IDisposable Open()
{
Console.WriteLine("Open!!");
return this;
}
public void Close()
{
Console.WriteLine("Close!!");
}
internal void Write()
{
Console.WriteLine("Write!!");
//throw new Exception(); // optional, also works
}
public void Dispose()
{
Close();
}
}
}

Related

C# retry method interception with free a AOP framework

I'm totally new to the AOP in C#. Currently, I'm interested to write a retry for a method that uses this technique.
So, based on the postsharp tut: https://doc.postsharp.net/method-interception
I've written this code:
[Serializable]
public class RetryAspect : MethodInterceptionAspect
{
private int _sleep;
private int _retries;
private object _expectedResult;
private object _defaultReturnValue;
public RetryAspect(object expectedResult, int waitBetweenCycles, int numberOfRetries) : this(expectedResult, waitBetweenCycles, numberOfRetries, null) { }
public RetryAspect(object expectedResult, int waitBetweenCycles, int numberOfRetries, object defaultReturnValue)
{
_expectedResult = expectedResult;
_sleep = waitBetweenCycles;
_retries = numberOfRetries;
_defaultReturnValue = defaultReturnValue;
}
public override void OnInvoke(MethodInterceptionArgs args)
{
int waitCount = 0;
while (!args.ReturnValue.Equals(_expectedResult))
{
args.Proceed();
if (waitCount++ < _retries)
{
Thread.Sleep(_sleep);
}
else
{
if (_defaultReturnValue != null)
{
args.ReturnValue = _defaultReturnValue;
}
break;
}
}
}
}
class Program
{
static int cnt = 0;
static void Main(string[] args)
{
Console.WriteLine(Test());
Console.ReadKey();
}
[RetryAspect(true, 1000, 5)]
public static bool Test()
{
Console.WriteLine("Test {0}", cnt);
if (cnt == 4)
{
return true;
}
else
{
cnt++;
return false;
}
}
}
Now, is there a way to achieve the same result by using a free/open source AOP framework? So far, I didn't found any useful example with a different AOP framework.
Althogh it is not AOP I can suggest you to use Polly:
Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry ...
You will just need to define your policy using it's fluent API:
var policy = Policy
.HandleResult<bool>(false)
//Or using one of WaitAndRetry overloads if you want to sleep between retries
.Retry(5);
And execute it:
policy.Execute(() => Test());

Making asynchronous API synchronous

I am connecting to an API to get some data that is defined like this:
A client object ClientConnection, which allows one to send requests.
A IApi interface that needs to be passed to the ClientConnection to receive callbacks.
Schematically it looks like this:
// defined in the API dll
public class ClientConnection {
public ClientConnection(IApi api) { ... }
public void request(int reqid, string reqdetails) { ... }
}
interface IApi
{
void receiveData(int reqid, string ans);
}
Now, obviously this is a fairly standard asynchronous way of doing things: send requests through a global object, with a requestid, and receive answers tagged with that requestid.
I want to create a wrapper that is synchronous. What would be the most natural way of doing this? Is there a smart way of using async await, instead of using thread locking and stuff?
class MyWrapper : IApi
{
private ClientConnection _client;
private int _reqToken = 0;
public MyWrapper()
{
_client = new ClientConnection(this);
}
public string getData(string reqdetails)
{
_client.request(_reqToken++, reqdetails);
// what to do here?
}
public void receiveData(int reqid, string data) {
// what to do here?
}
}
Didn't test the code below, but it should give you the idea. Basically you can use ManualResetEvent to be signalled when you receive your result (and don't ever call this without proper timeout):
class MyWrapper : IApi {
private ClientConnection _client;
// here you store your requests
private Dictionary<int, PendingRequest> _pendingRequests = new Dictionary<int, PendingRequest>();
private int _reqToken = 0;
public MyWrapper() {
_client = new ClientConnection(this);
}
public string getData(string reqdetails, TimeSpan timout) {
// if this is multithreaded - lock over _pendingRequests when you add\remove requests there
// and when you increment your _reqToken, or use concurrent collection
using (var token = new PendingRequest()) {
var id = _reqToken;
// lock here
_pendingRequests.Add(id, token);
_client.request(id, reqdetails);
// and here use Interlocked.Increment
_reqToken++;
if (!token.Signal.WaitOne(timout)) {
// and here
_pendingRequests.Remove(id);
// timeout
throw new Exception("timout");
}
// if we are here - we have the result
return token.Result;
}
}
public void receiveData(int reqid, string data) {
// here you might need to lock too
if (_pendingRequests.ContainsKey(reqid)) {
var token = _pendingRequests[reqid];
_pendingRequests.Remove(reqid);
token.Complete(data);
}
}
private class PendingRequest : IDisposable {
public PendingRequest() {
Signal = new ManualResetEvent(false);
}
public ManualResetEvent Signal { get; private set; }
public string Result { get; private set; }
public void Complete(string result) {
this.Result = result;
Signal.Set();
}
public void Dispose() {
Signal.Dispose();
}
}
}

Efficient multiple type checks upon an incoming packet

I have an abstract Packetclass to define the basic packet in my networking application. Once either the server or the client receives a packet, I only get the Packet object. I want to test for the type using is but it seems to me the casting is redundant when the is test succeeds. Using as would also work, but it requires one variable for each type I want to check. Isn't that inefficient? How can you test an object with many types in an efficient way? Here's an example:
public void HandlePacket(Packet packet)
{
MessagePacket messagePacket = packet as MessagePacket;
PingPacket pingPacket = packet as PingPacket;
if (messagePacket != null)
{
//Handle message packet
}
else if (pingPacket != null)
{
//Handle ping packet
}
else if ...
}
How about double dispatch?
class Message {
public abstract void Dispatch(MessageHandler handler);
}
class PacketMessage: Message {
override void Dispatch(MessageHandler handler) {
handler.HandlePacket(this);
}
}
class PingMessage: Message {
override void Dispatch(MessageHandler handler) {
handler.HandlePing(this);
}
}
class MessageHandler {
void HandleMessage(Message message) {
message.Dispatch(this);
}
void HandlePacket(PacketMessage packet) {
...
}
void HandlePing(PingMessage ping) {
...
}
}
I would go the route of is and specifically have methods in place for handling specific Packet types.
public void HandlePacket(Packet packet)
{
if (packet is MessagePacket)
{
HandleMessagingPacket((MessagePacket)packet);
}
else if (pingPacket is PingPacket)
{
HandlePingPacket((PingPacket)packet);
}
else if ...
}
There isn't much you can do aside from dynamic as mentioned in the comments. I prefer this route due separating logic between types and not even needing a variable other than packet.
Another option would be to set up a Dictionary<Type, Action> and build your handlers in there first. The only gotcha is the fact you now have to double check you got the correct packet type in the handler.
public class MyPacketHandler
{
Dictionary<Type, Action<Packet>> _packetHandlers = new Dictionary<Type, Action<Packet>>();
public MyPacketHandler()
{
_packetHandlers.Add(typeof(MessagePacket), HandleMessagePacket);
_packetHandlers.Add(typeof(PingPacket), HandlePingPacket);
}
public void HandlePacket(Packet packet)
{
var type = packet.GetType();
if(!_packetHandlers.Contains(type))
throw new NotSupportedException(type.Name + " is not supported");
_packetHandlers[type].Invoke(packet);
}
public void HandleMessagePacket(Packet packet)
{
var messagePacket = packet as MessagePacket;
if(packet == null)
throw new Exception("oops");
}
}
Note: The above is fully untested...
An extensible approach to consider (largely simplified/condensed, can be taken further/improved where needed). No efficiency claims.
public interface IPacket
{
string PacketType { get; }
object Payload { get; }
}
public interface IPacketHandler
{
string PacketType { get; }
void Handle(IPacket packet);
}
public class MessagePacket : IPacket, IPacketHandler
{
public string PacketType { get { return this.GetType().Name; } }
public object Payload { get; private set; }
public void Handle(IPacket packet)
{
// ...
}
}
public class PingPacket : IPacket, IPacketHandler
{
public string PacketType { get { return this.GetType().Name; } }
public object Payload { get; private set; }
public void Handle(IPacket packet)
{
// ...
}
}
public class PacketReceiver
{
private readonly Dictionary<string, IPacketHandler> packetHandlerLookup;
// inject handlers using favored approach...
public PacketReceiver(IPacketHandler[] handlerReferences)
{
this.packetHandlerLookup = handlerReferences
.ToDictionary(h => h.PacketType);
}
public void Receive(IPacket packet)
{
IPacketHandler handler;
this.packetHandlerLookup.TryGetValue(packet.PacketType, out handler);
if (handler == null)
{
throw new Exception(string.Format(
"Unknown packet handler for {0}",
packet.PacketType));
}
handler.Handle(packet);
}
}

ContextBoundObject Throws a Remoting Error After Await

I have some logging code that was written to intercept method calls using ContextBoundObject s and a ContextAttribute. The code is based on a Code Project sample.
This all worked fine until we started using this library with code that leverages async and await. Now we get remoting errors when running the code. Here is a simple example that reproduces the issue:
public class OhMyAttribute : ContextAttribute
{
public OhMyAttribute() : base("OhMy")
{
}
}
[OhMy]
public class Class1 : ContextBoundObject
{
private string one = "1";
public async Task Method1()
{
Console.WriteLine(one);
await Task.Delay(50);
Console.WriteLine(one);
}
}
When we invoke Method1 we get the following RemotingException on the second Console.WriteLine:
Remoting cannot find field 'one' on type 'WindowsFormsApplication1.Class1'.
Is there any way to get around this problem using built in C# methods or do we have to look at an alternative solution like PostSharp?
Short answer: Remoting calls do not work on private fields. The async/await rewriting causes an attempt to make a remoting call on a private field.
The issue can be reproduced without async/await. And demonstrating it this way is helpful in understanding what is going on in the async/await case:
[OhMy]
public class Class2 : ContextBoundObject
{
private string one = "1";
public void Method1()
{
var nc = new NestedClass(this);
}
public class NestedClass
{
public NestedClass(Class2 c2)
{
Console.WriteLine(c2.one); // Note: nested classes are allowed access to outer classes privates
}
}
}
static void Main(string[] args)
{
var c2 = new Class2();
// This call causes no problems:
c2.Method1();
// This, however, causes the issue.
var nc = new Class2.NestedClass(c2);
}
Let's walk through what happens line by line:
In Main, we start out in Context0
Since Class2 is a ContextBoundObject and since the OhMyAttribute considers the current context unacceptable, an instance of Class2 is created in Context1 (I'll call this c2_real, and what is returned and stored in c2 is a remoting proxy to c2_real.
When c2.Method1() is called, it is called on the remote proxy. Since we are in Context0, the remote proxy realizes it is not in the correct context so it switches to Context1, and the code within Method1 is executed.
3.a Within Method1 we call the NestedClass constructor which uses c2.one. In this case, we are already in Context1, so the c2.one requires no context switches and so we are using the c2_real object directly.
Now, the problematic case:
We create a new NestedClass passing in the remote proxy c2. No context switches occur here because NestedClass is not a ContextBoundObject.
Within the NestedClass ctor, it access c2.one. The remote proxy notices that we are still in Context0, and so it attempts to remote this call to Context1. This fails because c2.one is a private field. You'll see in Object.GetFieldInfo it is only looking for Public fields:
private FieldInfo GetFieldInfo(String typeName, String fieldName)
{
// ...
FieldInfo fldInfo = t.GetField(fieldName, BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.IgnoreCase);
if(null == fldInfo)
{
#if FEATURE_REMOTING
throw new RemotingException(String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_BadField"),
fieldName, typeName));
// ...
}
return fldInfo;
}
So, How does async/await end up causing this same issue?
The async/await causes your Class1 to get rewritten such that it uses a nested class with a state machine (used ILSpy to generate):
public class Class1 : ContextBoundObject
{
// ...
private struct <Method1>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder <>t__builder;
public Class1 <>4__this;
private TaskAwaiter <>u__$awaiter1;
private object <>t__stack;
void IAsyncStateMachine.MoveNext()
{
try
{
int num = this.<>1__state;
if (num != -3)
{
TaskAwaiter taskAwaiter;
if (num != 0)
{
Console.WriteLine(this.<>4__this.one);
taskAwaiter = Task.Delay(50).GetAwaiter();
if (!taskAwaiter.IsCompleted)
{
this.<>1__state = 0;
this.<>u__$awaiter1 = taskAwaiter;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Class1.<Method1>d__0>(ref taskAwaiter, ref this);
return;
}
}
else
{
taskAwaiter = this.<>u__$awaiter1;
this.<>u__$awaiter1 = default(TaskAwaiter);
this.<>1__state = -1;
}
taskAwaiter.GetResult();
taskAwaiter = default(TaskAwaiter);
Console.WriteLine(this.<>4__this.one);
}
}
catch (Exception exception)
{
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
this.<>1__state = -2;
this.<>t__builder.SetResult();
}
// ...
}
private string one = "1";
public Task Method1()
{
Class1.<Method1>d__0 <Method1>d__;
<Method1>d__.<>4__this = this;
<Method1>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<Method1>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <Method1>d__.<>t__builder;
<>t__builder.Start<Class1.<Method1>d__0>(ref <Method1>d__);
return <Method1>d__.<>t__builder.Task;
}
}
The important thing to notice is that
It's created a nested structure which has access to the privates of Class1
The this variable is lifted and stored in the nested class.
So, what happens here is that
On the initial call to c1.Method1() the remoting proxy notices we are in Context0, and that it needs to switch to Context1.
Eventually, MoveNext is called, and c1.one is called. Since we are already in Context1, no context switch is necessary (so the issue doesn't occur).
Later, since a continuation was registered, a call to MoveNext will occur again to execute the rest of the code after the await. However, this call to MoveNext will not occur inside a call to one of Class1's methods. Thus, when the code c1.one is executed this time, we will be in Context0. The remoting proxy notices we are in Context0, and attempts a context switch. This causes the same failure as above since c1.one is a private field.
Workaround:
I'm not sure of a general workaround, but for this specific case you can work around the issue by not using the this reference in the method. I.e.:
public async Task Method1()
{
var temp = one;
Console.WriteLine(temp);
await Task.Delay(50);
Console.WriteLine(temp);
}
Or switch to using a private property instead of a field.
Here is a more general workaround.
It has the following deficiencies:
It does not support changing the SynchronizationContext within the ContextBoundObject. It will throw in that case.
It does not support the case of using await when SynchronizationContext.Current is null and the TaskScheduler.Current is not the TaskScheduler.Default. In this scenario, normally await would capture the TaskScheduler and use that to post the remainder of the work, but since this solution sets the SynchronizationContext the TaskScheduler would not be captured. Thus, when this situation is detected, it will throw.
It does not support using .ConfigureAwait(false) since that will cause the SynchronizationContext to not be captured. Unfortunately, I could not detect this case. However, if the user does want to get .ConfigureAwait(false) like behavior for the underlying pass-through SynchronizationContext, they can use a custom awaiter (see https://stackoverflow.com/a/22417031/495262).
One interesting thing here is that I've attempted to create a "pass through" SynchronizationContext. That is, I didn't want to overwrite any existing SynchronizationContext, but rather retain its behavior and layer on top of it the behavior of doing the work in the proper context. Any comments on a better approach are welcome.
using System;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var c1 = new Class1();
var t = c1.Method1();
Func<Task> f = c1.Method1;
f.BeginInvoke(null, null);
Console.ReadKey();
}
}
[MyContext]
public class Class1 : ContextBoundObject
{
private string one = "1";
public async Task Method1()
{
Console.WriteLine(one);
await Task.Delay(50);
Console.WriteLine(one);
}
}
sealed class MyContextAttribute : ContextAttribute
{
public MyContextAttribute()
: base("My")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
if (ctorMsg == null)
throw new ArgumentNullException("ctorMsg");
ctorMsg.ContextProperties.Add(new ContributeInstallContextSynchronizationContextMessageSink());
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
return false;
}
}
sealed class ContributeInstallContextSynchronizationContextMessageSink : IContextProperty, IContributeServerContextSink
{
public ContributeInstallContextSynchronizationContextMessageSink()
{
}
public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
return new InstallContextSynchronizationContextMessageSink(nextSink);
}
public string Name { get { return "ContributeInstallContextSynchronizationContextMessageSink"; } }
public bool IsNewContextOK(Context ctx)
{
return true;
}
public void Freeze(Context ctx)
{
}
}
sealed class InstallContextSynchronizationContextMessageSink : IMessageSink
{
readonly IMessageSink m_NextSink;
public InstallContextSynchronizationContextMessageSink(IMessageSink nextSink)
{
m_NextSink = nextSink;
}
public IMessageSink NextSink
{
get { return m_NextSink; }
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
var contextSyncContext = new ContextSynchronizationContext(SynchronizationContext.Current);
var syncContextReplacer = new SynchronizationContextReplacer(contextSyncContext);
DelegateMessageSink.SyncProcessMessageDelegate replySyncDelegate = (n, m) => SyncProcessMessageDelegateForAsyncReply(n, m, syncContextReplacer);
var newReplySink = new DelegateMessageSink(replySink, replySyncDelegate, null);
return m_NextSink.AsyncProcessMessage(msg, newReplySink);
}
public IMessage SyncProcessMessage(IMessage msg)
{
var contextSyncContext = new ContextSynchronizationContext(SynchronizationContext.Current);
using (new SynchronizationContextReplacer(contextSyncContext))
{
var ret = m_NextSink.SyncProcessMessage(msg);
return ret;
}
}
private IMessage SyncProcessMessageDelegateForAsyncReply(IMessageSink nextSink, IMessage msg, SynchronizationContextReplacer syncContextReplacer)
{
syncContextReplacer.Dispose();
return nextSink.SyncProcessMessage(msg);
}
private void PreChecks()
{
if (SynchronizationContext.Current != null)
return;
if (TaskScheduler.Current != TaskScheduler.Default)
throw new InvalidOperationException("InstallContextSynchronizationContextMessageSink does not support calling methods with SynchronizationContext.Current as null while Taskscheduler.Current is not TaskScheduler.Default");
}
}
sealed class SynchronizationContextReplacer : IDisposable
{
SynchronizationContext m_original;
SynchronizationContext m_new;
public SynchronizationContextReplacer(SynchronizationContext syncContext)
{
m_original = SynchronizationContext.Current;
m_new = syncContext;
SynchronizationContext.SetSynchronizationContext(m_new);
}
public void Dispose()
{
// We don't expect the SynchronizationContext to be changed during the lifetime of the SynchronizationContextReplacer
if (SynchronizationContext.Current != m_new)
throw new InvalidOperationException("SynchronizationContext was changed unexpectedly.");
SynchronizationContext.SetSynchronizationContext(m_original);
}
}
sealed class ContextSynchronizationContext : PassThroughSynchronizationConext
{
readonly Context m_context;
private ContextSynchronizationContext(SynchronizationContext passThroughSyncContext, Context ctx)
: base(passThroughSyncContext)
{
if (ctx == null)
throw new ArgumentNullException("ctx");
m_context = ctx;
}
public ContextSynchronizationContext(SynchronizationContext passThroughSyncContext)
: this(passThroughSyncContext, Thread.CurrentContext)
{
}
protected override SynchronizationContext CreateCopy(SynchronizationContext copiedPassThroughSyncContext)
{
return new ContextSynchronizationContext(copiedPassThroughSyncContext, m_context);
}
protected override void CreateSendOrPostCallback(SendOrPostCallback d, object state)
{
CrossContextDelegate ccd = () => d(state);
m_context.DoCallBack(ccd);
}
}
abstract class PassThroughSynchronizationConext : SynchronizationContext
{
readonly SynchronizationContext m_passThroughSyncContext;
protected PassThroughSynchronizationConext(SynchronizationContext passThroughSyncContext)
: base()
{
m_passThroughSyncContext = passThroughSyncContext;
}
protected abstract void CreateSendOrPostCallback(SendOrPostCallback d, object state);
protected abstract SynchronizationContext CreateCopy(SynchronizationContext copiedPassThroughSyncContext);
public sealed override void Post(SendOrPostCallback d, object state)
{
var d2 = CreateSendOrPostCallback(d);
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.Post(d2, state);
else
base.Post(d2, state);
}
public sealed override void Send(SendOrPostCallback d, object state)
{
var d2 = CreateSendOrPostCallback(d);
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.Send(d2, state);
else
base.Send(d2, state);
}
public sealed override SynchronizationContext CreateCopy()
{
var copiedSyncCtx = m_passThroughSyncContext != null ? m_passThroughSyncContext.CreateCopy() : null;
return CreateCopy(copiedSyncCtx);
}
public sealed override void OperationCompleted()
{
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.OperationCompleted();
else
base.OperationCompleted();
}
public sealed override void OperationStarted()
{
if (m_passThroughSyncContext != null)
m_passThroughSyncContext.OperationStarted();
else
base.OperationStarted();
}
public sealed override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
return m_passThroughSyncContext != null ?
m_passThroughSyncContext.Wait(waitHandles, waitAll, millisecondsTimeout) :
base.Wait(waitHandles, waitAll, millisecondsTimeout);
}
private SendOrPostCallback CreateSendOrPostCallback(SendOrPostCallback d)
{
SendOrPostCallback sopc = s => CreateSendOrPostCallback(d, s);
return sopc;
}
}
sealed class DelegateMessageSink : IMessageSink
{
public delegate IMessage SyncProcessMessageDelegate(IMessageSink nextSink, IMessage msg);
public delegate IMessageCtrl AsyncProcessMessageDelegate(IMessageSink nextSink, IMessage msg, IMessageSink replySink);
readonly IMessageSink m_NextSink;
readonly SyncProcessMessageDelegate m_syncProcessMessageDelegate;
readonly AsyncProcessMessageDelegate m_asyncProcessMessageDelegate;
public DelegateMessageSink(IMessageSink nextSink, SyncProcessMessageDelegate syncProcessMessageDelegate, AsyncProcessMessageDelegate asyncProcessMessageDelegate)
{
m_NextSink = nextSink;
m_syncProcessMessageDelegate = syncProcessMessageDelegate;
m_asyncProcessMessageDelegate = asyncProcessMessageDelegate;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return (m_asyncProcessMessageDelegate != null) ?
m_asyncProcessMessageDelegate(m_NextSink, msg, replySink) :
m_NextSink.AsyncProcessMessage(msg, replySink);
}
public IMessageSink NextSink
{
get { return m_NextSink; }
}
public IMessage SyncProcessMessage(IMessage msg)
{
return (m_syncProcessMessageDelegate != null) ?
m_syncProcessMessageDelegate(m_NextSink, msg) :
m_NextSink.SyncProcessMessage(msg);
}
}
}

How to process incoming commands using event arrays?

I'm currently working on a simple Client/Server model which sends packets within TCP packets (like HTTP) and the commands are basically ints (the first 4 bytes of each packet) and I'd like to work out an efficient way of how to process these commands.
The most obvious answer would be to write thousands of if's or do one huge switch statement with thousand cases, but isn't there any better way?
I'd like to create an array of events and then just raise the corresponding index so each int refers to one event which is named (such as MessageReceived). I'd also save time I think, so how could I work this out?
EDIT: The Server handles multiple connections, one for each client that is connected, so creating seperate connections for each command(s) isn't that useful in my case.
Sound like a job for enums!
enum YourEnum
{
DoThis,
DoThat
}
YourEnum foo = (YourEnum)yourInt;
Visual studio can even create your entire switch statement using the built in snippets and your code becomes very readable.
switch(foo)
becomes
switch(foo)
{
case YourEnum.DoThis:
break;
case YourEnum.DoThat:
break;
default:
break;
}
Update 1
This is a little scary from a maintainability point of view, but if you created a class like:
public class ActionProcessor
{
public void Process(int yourInt)
{
var methods = this.GetType().GetMethods();
if (methods.Length > yourInt)
{
methods[yourInt].Invoke(this, null);
}
}
public DoThis()
{
}
public DoThat()
{
}
or a little nicer but harder to maintain:
[AttributeUsageAttribute(AttributeTargets.Method,
Inherited = false,
AllowMultiple = false)]
public sealed class AutoActionAttribute : Attribute
{
public AutoActionAttibute(int methodID)
{
this.MethodID = methodID;
}
public int MethodID { get; set; }
}
public class ActionProcessor
{
public void Process(int yourInt)
{
var method = this.GetType().GetMethods()
.Where(x => x.GetCustomAttribute(typeof(AutoActionAttribute),
false) != null
&& x.GetCustomAttribute(typeof(AutoActionAttribute),
false).MethodID == yourInt)
.FirstOrDefault();
if (method != null)
{
method.Invoke(this, null);
}
}
[AutoAction(1)]
public DoThis()
{
}
[AutoAction(2)]
public DoThat()
{
}
}
Update 2 (Coding what I think Josh C. was talking about)
// Handles all incoming requests.
public class GenericProcessor
{
public delegate void ActionEventHandler(object sender, ActionEventArgs e);
public event ActionEventHandler ActionEvent;
public ProcessAction(int actionValue)
{
if (this.ActionEvent != null)
{
this.ActionEvent(this, new ActionEventArgs(actionValue));
}
}
}
// Definition of values for request
// Extend as needed
public class ActionEventArgs : EventArgs
{
public ActionEventArgs(int actionValue)
{
this.ActionValue = actionValue;
}
public virtual int ActionValue { get; private set; }
}
This you create the SomeActionProcessor that is responsible for some value:
// Handles a specific (or multiple) requests
public class SomeActionProcessor
{
public void HandleActionEvent(object sender, ActionEventArgs e)
{
if (e.ActionValue == 1)
{
this.HandleAction();
}
}
private void HandleAction()
{
}
}
Then create the classes and wire them up:
GenericProcessor gp = new GenericProcessor();
SomeActionProcessor sap = new SomeActionProcessor();
gp.ActionEvent += sap.HandleActionEvent;
The fire away and sending the generic processor requests:
gp.ProcessAction(1);
You could possibly implement a publisher-subscriber model. Instead of having one listener, you would have many. Each listener would listen for at least one command. Then you can split your switch across multiple classes.

Categories