C# - How can I "overload" a delegate?

23,561

Solution 1

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.

Solution 2

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);
}
Share:
23,561
Lucas Gabriel Sánchez
Author by

Lucas Gabriel Sánchez

I'm a programmer. I've been a programmer for over a decade. I've love languages, I like to learn them and use as many as I can, and in no particular order these are the ones I used in my career: Action Script 3, for flash games C#, for Unity 3D games C++, for mobile games with cocos2d-x, and apps with JUCE Java, for Android games and apps, and for desktop apps a long time ago Objective-C, for iOS games and apps JavaScript, for Web and web services (nodejs) Go, for web services Python (2.x and 3.x), for internal tools and game servers I like to play around with different languages to build things and find interesting facts about programming, so I'm developing a new programming language (duh!) in a very slow pace, not only to create something, but also to learn the hows and whys of this lovely profession. The languages I'm interested or learning right now: Lisp, Erlang and Elixir

Updated on April 21, 2020

Comments

  • Lucas Gabriel Sánchez
    Lucas Gabriel Sánchez about 4 years

    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.