4

I'm building a system a bit like LINQ, and in doing it, am trying to support polymorphic callback handler lists, and am running into several kinds of problems. The short way to ask my question is to just show you some code. My new system supports "Groups" and groups have a vector of entry points (below, UPDATE and CHECKPT) and each element on the vector is a polymorphic list of delegates, which I'll call back using reflection.

So, sample code:

namespace ConsoleApplication1
{

    internal delegate void GroupISDHandler(int i, string s, double d);
    class Group
    {
        public class myHandlers {
            internal List<Delegate> hList = new List<Delegate>();
            public static myHandlers operator +(myHandlers a, Delegate b) {
                a.hList.Add(b);
                return a;
            }
        }

        public class mimicVector {
            public List<myHandlers> ListofhLists = new List<myHandlers>();
            public myHandlers this[int i] { get { return ListofhLists[i]; } set { ListofhLists[i] = value; } }
        }

        public mimicVector handlers = new mimicVector();

        public Group(string name) { ... }
    }

    class Program
    {
        internal const int UPDATE = 0;
        internal const int CHECKPT = 1;

        public static void Main()
        {
            Group g = new Group("group name");
            g.handlers[UPDATE] += (GroupISDHandler)delegate(int x, string s, double d) {
                Console.WriteLine("my int,string,double handler was called, with x = {0}, s = {1}, d = {2}", 
                     x,s,d);
            };
        }
    }
}

My questions centers on the registration line. Why can't C# infer the types so that I could omit the cast and the new delegate type entirely? I would think that from

 g.handlers[UPDATE] += delegate(int x, string s, double d) {
     Console.WriteLine(....);
 };

C# could infer the needed type signature. delegate() would be a kind of anonymous type and C# would just generate something like

private delegate void _atype1(int _a0, string _a1, double _a2)

and then insert (Delegate)(_atype1) before compiling the line. Thus my user won't need to declare a delegate type (which currently forces her to type the argument list twice, in effect).

I do have System.Linq since I'm on VS 2010. So if LINQ can somehow infer the needed casts...

jball
  • 24,791
  • 9
  • 70
  • 92
Ken Birman
  • 1,088
  • 8
  • 25
  • I just noticed that you want to get rid of the Cast also, why do you need the parameters? or are they always going to be 3 ? – Sebastian Piu Dec 11 '10 at 17:42
  • The parameters will vary; one incoming message might have an int and a string; a second might have an array of FooBars, etc. My delivery logic does an upcall for each match. – Ken Birman Dec 11 '10 at 18:20
  • (To add just a bit of explanation: the incoming messages that trigger the upcalls contain data that needs to match at least one of these callbacks. When you send a multicast to a group, I check to make sure it matches some legal type signature for some upcall. So: the parameters come from the message and their types will match, etc). – Ken Birman Dec 11 '10 at 19:23

2 Answers2

2

you should be able to do it this way:

g.handlers[UPDATE] += (GroupISDHandler)((x, s, d) => Console.WriteLine( "my int,string,double handler was called, with x = {0}, s = {1}, d = {2}", x, s, d));

another option would be:

have a class named ´Parameters´ that is a container for whatever the user can send, might be defined types if they never change, or a list of objects if you pretend to send and receive different amount of parameters. Then instead of a Delegate, you would take Action that equals a delegate that takes one argument, and you could do your call without casting like this:

p => Console.WriteLine("x = {0}, s = {1}, d = {2}", p.x, p.s, p.d);

Sebastian Piu
  • 7,838
  • 1
  • 32
  • 50
  • That's an interesting idea. So in this version my user does need the cast but can avoid specifying the parameter types and doesn't need to say "delegate". I like that. Quite a bit less messy. Still, a shame that the declaration ends up so far from the code: a person looking at this won't know the types of x, s and d. – Ken Birman Dec 11 '10 at 18:21
0

Turns out that the answer is basically this: while you can do the inference in the kinds of situations I had in mind, the C# owners want completely general solutions and polymorphism makes the type inference problem too hard to solve in a sufficiently general way, in their view. I myself disagree since I end up typing all my type signatures twice, but that's their reasoning.

Ken Birman
  • 1,088
  • 8
  • 25