creating actions based on specific fields having specific values
Imagine I have a C# app sitting on a server somewhere that is creating instances of the Item
class and publishing them on a messaging service.
class Item
{
public int ID1, ID2, ID3;
public double Value1, Value2, Value3;
}
Now I have another C# app on a desktop somewhere listening to these messages. I want to be able to create callbacks based on specified values of the ID# fields. For example, "call this method whenever a message comes in where ID1 = 2, ID2 = 160, and ID3 = anything". I think this would be straightforward if I used string key-value pairs, but ideally I could do this without giving up static typing. I imagine this requires reflection, but I'm not entirely sure where to start.
I'm picturing the app creating an instance of Item
with the required ID# values (let's say -1 means unspecified), and passing that into a RegisterCallback
method of som开发者_开发技巧e object ItemListener
. Then whenever ItemListener
receives a new Item
message, it can check for any callbacks that match, and act accordingly. Is this a reasonable design? Any suggestions on what to look at to implement it?
class ConditionalCallback()
{
public Predicte<Item> Predicate {get; set;}
public Action<Item> Callback {get; set;}
}
List<ConditionalCallback> callbacks = new List<ConditionalCallback>();
public AddCallBack(Predicte<Item> pred, Action<Item> callback)
{
callbacks.Add(new ConditionalCallback {
Predicate = pred,
Callback = callback
});
}
void HandleItem(Item item)
{
foreach(var cc in callbacks)
if (cc.Predicate(item))
cc.Callback(item);
}
//
AddCallBack( i=> i.ID1 = 2 && i.ID2 = 160 && i.ID3 = anything", MyCallback);
It's possible to do without giving up type safety. What you basically need is a tuple type (.NET 4.0 has this, but if you are not using that, you can create your own easily) where the members are nullable types of the id types that you want to match on.
You would then use instances of these types as keys in a dictionary where the value is the delegate that you would execute on a match. For example, your key type would look like this:
struct ItemKey
{
public int? ID1, ID2, ID3;
public double? Value1, Value2, Value3;
}
Then, for your example of processing a message where ID1 = 1, ID2 = 160, and ID3 = anything, you would instantiate the key for the delegate in the dictionary like this:
new ItemKey { ID1 = 1, ID2 = 160 }
Note, it's very important here that ItemKey is a structure, as it provides the correct implementations of GetHashCode and Equals which are essential to being keyed in the dictionary correctly.
A drawback of this design is that you have to be explicit for all the kinds of partial matches that are possible.
For example, if you wanted a delegate to be processed when the ID1 = 2, and another one where you want to process when ID1 = 2 and ID2 = 3, you have to specify those cases specifically. This can cause the dictionary to grow very very fast if you have many permutations.
If this is the case, you might want to look into a database solution of some kind where you store the ID values in separate columns, and then do a lookup on the appropriate columns (filtering on selective columns). Then, you would have a type name in a field on the row, which you could use to create a type instance through reflection, which implements an interface or derives from a base type, which you can create a variable of and call the method which performs the functionality.
精彩评论