2010-09-19 16 views
21

Primero, estaba leyendo algunos foros y la ayuda en MSDN y todos dicen que un delegado no puede estar sobrecargado.C# - ¿Cómo puedo "sobrecargar" a un delegado?

Ahora, quiero tener algo como esto:

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

Así que, como se sabe, no se puede hacer esto, porque OneDelegate sólo se refiere a la primera y no la segunda. Pero, ¿hay alguna manera de hacer esto? ¿o algo así?

PS1: Quiero tener cualquier cantidad de declaraciones de OneDelegate, no solo una o dos.
PS2: Perdón por mi mal inglés.

+2

Lo más cerca que puede obtener es sobrecargar utilizando genéricos, exactamente como todas las sobrecargas Action <> y Func <>. (Donde los argumentos genéricos representan los tipos de parámetros y los tipos de retorno.) Por supuesto, una vez que llegas tan lejos, surge la pregunta de por qué no usar Action <> y Func <> en primer lugar. –

+1

Quiero tener solo UN TIPO de esta función para que pueda decir "¡Oye, aquí tienes una función, llámala!". Y no puedo hacer eso con Action <> AND Func <>. –

Respuesta

32

Imagine por un momento esto fue posible. Supongo que podría haber un delegado sobrecargado:

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

Ahora imagino que declara una variable de este tipo y luego asignar una función a la misma, por ejemplo:

OneDelegate myDelegate = StringMethod; 

donde StringMethod se declara así:

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

Ahora se pasa a myDelegate algún otro código, y que el código hace esto:

myDelegate(47); 

¿Qué espera que suceda en este caso? ¿Cómo puede el tiempo de ejecución llamar al StringMethod() con un argumento entero?

Si realmente quiere un delegado que puede tomar cualquier conjunto de parámetros en absoluto, entonces la única opción es tener uno con un params object[] matriz:

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

Pero entonces usted tendrá que asignar a es una función que realmente puede manejar cualquier matriz de objetos, por ejemplo:

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

Como puede ver, esto se complica demasiado rápido. Por lo tanto, le presento que si necesita un delegado de este tipo, probablemente haya cometido un error en algún lugar de su diseño arquitectónico. Identifique este defecto y arregle el diseño antes de continuar con la implementación, ya que de lo contrario se verá afectado el mantenimiento de su código.

+1

¿Quizás el "error" en su diseño arquitectónico fue usar C#, entonces? F # (y otros lenguajes funcionales con coincidencia de patrones) no tiene problema con una función que no lleva nada o una lista. – Gabe

+0

@Gabe: Es suficiente, pero tenga en cuenta que F # es un paradigma de programación completamente diferente, que puede o no ser apropiado para su proyecto en particular. – Timwi

+3

No estoy sugiriendo que quiera usar F #. Simplemente estoy en desacuerdo con la idea de que encontrarse con una limitación de C# probablemente sea causada por un diseño deficiente del programa en lugar de un diseño deficiente (o simplemente un defecto) de C#. – Gabe

6

La clase Action "hace esto". Es un delegado con las plantillas, lo que puede tener un delegado de esta manera:

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

func() { 
    D<object> d1; 
} 

Esto es probablemente lo más cerca que se va a conseguir, es decir, se necesita un tipo de plantilla como un parámetro.

Editar: Según los comentarios, supongo que está después de pasar un delegado a otra función. Usted puede lograrlo pasando los argumentos también. Desafortunadamente no puede hacer esto sin el uso de un parámetro params a 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); 
} 
Cuestiones relacionadas