2011-03-22 17 views
8

¿Hay alguna forma de almacenar un delegado sin vincularlo a un objeto como lo hace con un MethodInfo? En este momento estoy almacenando un MethodInfo para poder darle el objeto para llamar al método. Pero prefiero que sea un delegado. ¿Como hay un atributo que le dice a .net que el primer parámetro es "esto"?C# Delegate no vinculado a una instancia?

MethodInfo mi; 
Action<string> func; 
mi.Invoke(this,new object[]{str}); 
func(this, str); //Is this possible with a delegate? 
+0

podría reformular la pregunta con algo más de detalles, creo que lo tengo en parte, pero no Por supuesto. –

+0

Agregué un ejemplo de lo que quiero decir. Básicamente, ¿es posible tener un delegado sin una referencia de objeto y darle un objeto cuando lo llames? – Will

+1

Cambié el título de su pregunta para hacerlo más claro. Siéntase libre de retroceder si no le gusta;) –

Respuesta

11

Lo que quiere se llama open instance delegate. No se admite directamente en el lenguaje C#, pero CLR lo admite.

Básicamente, un delegado de instancia abierto es lo mismo que un delegado normal, pero toma un parámetro adicional para this antes de los parámetros normales, y tiene un objetivo nulo (como un delegado para un método estático). Por ejemplo, la instancia equivalente abierta de Action<T> sería:

delegate void OpenAction<TThis, T>(TThis @this, T arg); 

Aquí está un ejemplo completo:

void Main() 
{ 
    MethodInfo sayHelloMethod = typeof(Person).GetMethod("SayHello"); 
    OpenAction<Person, string> action = 
     (OpenAction<Person, string>) 
      Delegate.CreateDelegate(
       typeof(OpenAction<Person, string>), 
       null, 
       sayHelloMethod); 

    Person joe = new Person { Name = "Joe" }; 
    action(joe, "Jack"); // Prints "Hello Jack, my name is Joe" 
} 

delegate void OpenAction<TThis, T>(TThis @this, T arg); 

class Person 
{ 
    public string Name { get; set; } 

    public void SayHello(string name) 
    { 
     Console.WriteLine ("Hi {0}, my name is {1}", name, this.Name); 
    } 
} 

Tenga una mirada en this article para más detalles.

+0

Es una pena que C# no lo soporte directamente. Gracias por la información: D. – Will

5

Usted puede utilizar el método Delegate.CreateDelegate para crear un delegado inflexible de tipos para un MethodInfo.

Si usted no sabe la firma del método en tiempo de compilación, puede crear un uso de Reflexión Func<...>, o crear una expresión lambda que invoca el MethodInfo:

MethodInfo methodInfo = ...; 
object thisObj = ...; 
Func<object[]> callMethod = args => methodInfo.Invoke(thisObj, args); 

(Esto se llama currificación)

Tenga en cuenta que esto todavía tendrá el rendimiento de la reflexión cada vez que se llama al delegado, a diferencia de Delegate.CreateDelegate.

+0

No pensé en usar lambda para hacerlo más agradable, gracias. – Will

0

Un delegado es esencialmente solo un MethodInfo (en realidad, un MethodBase) y una referencia de objeto, con algunos punteros internos para el rendimiento. Entonces, si tiene un MethodInfo, básicamente tiene un delegado independiente. ¿Cuál es su caso de uso específico?

+1

Funcionalmente, sí, es más o menos lo mismo. Pero MethodInfo.Invoke es mucho más lento que invocar a un delegado ... –

+0

@Thomas Levesque: De acuerdo. Para llamadas repetidas, el rendimiento puede mejorarse llamando a 'Delegado'.CreateDelegate() 'para crear un delegado encuadernado, pero yo supongo que para que un enlace de llamada de descarte, se unen-call-descarte patrón, que no ofrecería ninguna ventaja de rendimiento. –

0

Por qué no simplemente

Action<T, string> unbound = (This, str) => This.Method(str); 

para que pueda

unbound(instanceA, "hello"); 
unbound(instanceB, "world"); 

o incluso

Action<string> bound = str => unbound(instanceC, str); 
Cuestiones relacionadas