26

First, I was reading some forums and the help in MSDN and all says that a delegate can't be overloaded.

Now, I want to have something like this:

public delegate void OneDelegate();
public delegate void OneDelegate(params object[] a);

public void DoNothing(params object[] a) {}
public void DoSomething() { /* do something */ }

private OneDelegate someFunction;

someFunction = new OneDelegate(DoSomething);
someFunction = new OneDelegate(DoNothing);

So, like you know, you CAN'T do this, because OneDelegate only refers to the first one and not the second one. But, is there a way for doing this? or something like that?

PS1: I want to have any number of OneDelegate declarations, not just one or two.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Lucas Gabriel Sánchez
  • 40,116
  • 20
  • 56
  • 83
  • 2
    The closest you can get is overloading using generics, exactly like all the Action<> and Func<> overloads. (Where the generic arguments represent the parameter types and the return types.) Of course, once you go that far, it begs the question of why not just use Action<> and Func<> in the first place? – Kirk Woll Sep 19 '10 at 23:57
  • 1
    I want to have only ONE TYPE of this function so I can say "Hey, here you got a Function, call it!". And I can't do that with Action<> AND Func<>. – Lucas Gabriel Sánchez Sep 20 '10 at 00:05

2 Answers2

44

Imagine for a moment this was possible. Suppose I could have an overloaded delegate:

public delegate void OneDelegate(int i);
public delegate void OneDelegate(string s);

Now imagine I declare a variable of this type and then assign a function to it, for example:

OneDelegate myDelegate = StringMethod;

where StringMethod is declared thusly:

public void StringMethod(string s) { Console.WriteLine(s); }

Now you pass myDelegate to some other code, and that code does this:

myDelegate(47);

What do you expect to happen in this case? How can the runtime call StringMethod() with an integer argument?

If you really want a delegate that can take any set of parameters at all, then the only option is to have one with a params object[] array:

public delegate void OneDelegate(params object[] parameters);

But then you will have to assign to it a function that can actually handle any object array, for example:

public void MyMethod(params object[] parameters)
{
    if (parameters == null || parameters.Length == 0)
        throw new ArgumentException("No parameters specified.");
    if (parameters.Length > 1)
        throw new ArgumentException("Too many parameters specified.");

    if (parameters[0] is int)
        IntMethod((int) parameters[0]);
    else if (parameters[0] is string)
        StringMethod((string) parameters[0]);
    else
        throw new ArgumentException("Unsupported parameter type.");
}

As you can see, this gets messy real quick. Therefore, I submit to you that if you need such a delegate, you have probably made a mistake somewhere in your architectural design. Identify this flaw and fix the design before you proceed with the implementation, as otherwise the maintainability of your code will suffer.

Timwi
  • 65,159
  • 33
  • 165
  • 230
  • 2
    Perhaps the "mistake" in his architectural design was to use C#, then? F# (and other functional languages with pattern matching) has no problem with a function that takes either nothing or a list. – Gabe Sep 20 '10 at 04:31
  • @Gabe: Fair enough — but keep in mind that F# is a completely different programming paradigm, which may or may not be appropriate for his particular project. – Timwi Sep 20 '10 at 04:40
  • 6
    I'm not suggesting that he wants to use F#. I just disagree with the notion that running into a limitation of C# is likely to be caused by poor design of the program rather than poor design (or just a shortcoming) of C#. – Gabe Sep 20 '10 at 04:58
  • 3
    @Gabe: We are talking about different things. You said F# has no problem with a function that takes *either nothing or a list*. Nor does C#. My answer is talking about a function that takes *any arguments at all*. The OP said in the question, *“I want to have any number of OneDelegate declarations, not just one or two.”* From that I concluded that the overloads he presented were just an example. – Timwi Sep 20 '10 at 05:45
  • Timwi: You can also write a function in F# that takes either a string or an int. It's hard to know what the OP wants, but it sounds like it would be easy to do in F#. – Gabe Sep 20 '10 at 06:41
  • @Timwi & Gabe: This is a proyect for my university, I HAVE to use C# and I'm porting a library that I already use in my work (one that I made) for ActionScript 3.0 (AS3 have functions that can be used as objects, not delegates) – Lucas Gabriel Sánchez Sep 20 '10 at 12:35
  • @unkiwii Then you should be able to use Func<>s. – Richard Anthony Hein Sep 20 '10 at 14:23
  • 2
    Ok, I give up. There is no way to having only ONE TYPE OF DELEGATE TO RULE THEM ALL! sad.. – Lucas Gabriel Sánchez Sep 21 '10 at 00:18
  • @unkiwii: It would probably not have been overly difficult to design .net such that a delegate could have more than one overload of `Invoke`, if `Delegate.Combine` were implemented differently. The constructor for a delegate with *n* overloads would need to accept *n* `MethodPtr` arguments, and languages would have had to be able to deal with that (extracting all appropriate overloads from a method group), but I'm not there would be a fundamental difficulty. I don't think there's anything fundamental that delegates can do that couldn't be done with generic interfaces... – supercat Nov 01 '12 at 23:09
  • ...had such things existed when .net 1.0 was created. The fact that compilers auto-generate the code to deal with delegates, and they don't auto-generate such code for interfaces, wouldn't be a factor if a specific style of interfaces had been designated as the proper means of passing methods. – supercat Nov 01 '12 at 23:11
7

The Action class "does this". It's a delegate with templates, so you can have a delegate like this:

public delegate void D<T>(params T[] arg);

func() {
    D<object> d1;
}

This is probably as close as you are going to get, i.e. you need a template type as a parameter.

Edit: Based on comments I guess you are after passing a delegate to another function. You can accomplish it by passing along the arguments as well. Unfortunately you cannot do this without the use of a params parameter to fire.

public void bar() {
    D<string> d = ...;
    fire(d, "first", "second");
    fire(d); // also works
}

public void fire<T>(D<T> f, params T[] args) {
    f(args);
}
Patrick
  • 17,669
  • 6
  • 70
  • 85