I have a need to provide the ability to plug an arbitrary C# class written by a third party into an existing program, so that it can process a stream of bytes.
This object (or its type) would be registered with a sending and receiving object. It would read bytes from the sending object, process them in some way, and pass them to the receiving object, like this:
Sender ==> Filter ==> Receiver
The prototype API for the filter class looks something like this:
// Reads the specified number of bytes from the receiver
public byte[] ReadBytes(int numberOfBytes)
// Writes the specified number of bytes to the sender.
public void WriteBytes(byte[] data)
How can I provide a relatively simple mechanism for registering the Filter object with the Sender and Receiver objects, and then hook up the methods so that the data bytes can be passed into the Filter object, and out the other side?
Caveats:
I'm not sure that I fully understand the problem, however from what you have described I'd probably have the filter and Sender both implement (or provide an instance of) Stream with CanRead returning false.
The filter would require an instance of Sender to read bytes from, and so filter would need to inherit from some base class that allowed someone to supply a source Stream, something along the lines of:
public abstract class FilterBase : Stream
{
private readonly Stream sender;
protected Stream Sender
{
get { return sender; }
}
public FilterBase(Stream sender)
{
this.sender = sender;
}
}
To "Register" the filter with a sender, you simply provide an instance of Stream from which the filter should read bytes.
Similarly, to "Register" the filter with the Receiver simply give it an instance of Stream (the filter) from which it should read bytes. (Alternatively you could provide a Type and have the reciever / sender create the filter instance - this is the bit I'm fuzzy on).
This easily allows you to chain any number of filters together.
For convenience FilterBase can implement many of the Stream methods and properties (most of them will just throw NotSupportedException anyway).
Alternatively you could define your own IStream (or IFilter) interface which uses just the methods that the reciever uses, but I'd still use the same chaining pattern where you "Register" a sender / reciever with a filter by providing a IStream instance.
Of course this only works if Receiver pulls bytes from Sender - if Sender instead pushes bytes to Receiver then your filter will need to implement the Write methods of stream instead of the Read methods and Receiver needs to inherit from (or provide a) Stream.
You can also do both if needed by having both Sender and Reciever inherit from (or provide a) Stream. This might get a bit confusing for anyone implementing a filter - the Write methods are messages to be pushed to the reciever and the Read methods are requests to read from the sender. You might want to create your own interface(s) to make it clear what the roles are, however again I'd still follow the same pattern - just with different method names.
You could encapsulate your API, along with the sender and receiver objects, in a StreamContext class and then pass the context object to the filter, which can implement an IFilter interface:
public class StreamContext
{
private Sender sender;
private Receiver receiver;
public byte[] ReadBytes(int numberOfBytes)
{
return readBytesFromSender(numberOfBytes);
}
public void WriteBytes(byte[] data)
{
writeToReceiver(data);
}
}
public interface IFilter
{
void Filter(StreamContext context);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With