C # - Как я могу «перегрузить» делегата? - PullRequest
22 голосов
/ 20 сентября 2010

Сначала я читал некоторые форумы и справку в MSDN, и все говорят, что делегат не может быть перегружен.

Теперь я хочу что-то вроде этого:

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);

Итак, как вы знаете, вы НЕ МОЖЕТЕ сделать этого, потому что OneDelegate относится только к первому, а не ко второму. Но есть ли способ сделать это? или что-то подобное?

PS1. Я хочу иметь любое количество объявлений OneDelegate, а не только одно или два.

Ответы [ 2 ]

35 голосов
/ 20 сентября 2010

Представьте на мгновение, что это возможно.Предположим, у меня может быть перегруженный делегат:

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

Теперь представьте, что я объявляю переменную этого типа, а затем назначаю ей функцию, например:

OneDelegate myDelegate = StringMethod;

где StringMethodобъявляется так:

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

Теперь вы передаете myDelegate другому коду, и этот код делает это:

myDelegate(47);

Что вы ожидаете в этом случае?Как может во время выполнения вызвать StringMethod() с целочисленным аргументом?

Если вы действительно хотите, чтобы делегат мог принимать любой набор параметров на всех , тогда единственный вариант - это иметь один сparams object[] массив:

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

Но тогда вам нужно будет назначить ему функцию, которая может фактически обрабатывать любой массив объектов, например:

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.");
}

Как вы можете видеть, это становится грязно очень быстро.Поэтому я утверждаю, что если вам нужен такой делегат, вы, вероятно, допустили ошибку где-то в своем архитектурном проекте.Выявите этот недостаток и исправьте дизайн, прежде чем приступить к реализации, так как в противном случае поддержка вашего кода пострадает.

7 голосов
/ 20 сентября 2010

Класс Action"делает это".Это делегат с шаблонами, поэтому у вас может быть такой делегат:

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

func() {
    D<object> d1;
}

Это, вероятно, так близко, как вы собираетесь получить, т.е. вам нужен тип шаблона в качестве параметра.1007 * Редактировать: на основе комментариев, я думаю, вы после передачи делегата в другую функцию.Вы можете сделать это, передав аргументы.К сожалению, вы не можете сделать это без использования параметра params для 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);
}
...