2009-06-04 9 views
7

Ho notato che la classe Delegate ha una proprietà Target, che (presumibilmente) restituisce l'istanza su cui verrà eseguito il metodo delegato. Voglio fare qualcosa di simile:Come creare un delegato su un metodo di istanza con una destinazione nullo?

void PossiblyExecuteDelegate(Action<int> method) 
{ 
    if (method.Target == null) 
    { 
     // delegate instance target is null 
     // do something 
    } 
    else 
    { 
     method(10); 
     // do something else 
    } 
} 

Quando si chiama, voglio fare qualcosa di simile:

class A 
{ 
    void Method(int a) {} 

    static void Main(string[] args) 
    { 
     A a = null; 
     Action<int> action = a.Method; 
     PossiblyExecuteDelegate(action); 
    } 
} 

ma ottengo un ArgumentException (delegato a un metodo di istanza non può avere un null 'questo ') quando provo a costruire il delegato. È quello che voglio fare e come posso farlo?

+0

Perché vuoi farlo? Hai istanze che sono null? –

risposta

15

Ahah! found it!

È possibile creare un delegato istanza aperta con un sovraccarico di CreateDelegate, utilizzando un delegato con la implicita 'questo' primo argomento esplicitamente specificato:

delegate void OpenInstanceDelegate(A instance, int a); 

class A 
{ 
    public void Method(int a) {} 

    static void Main(string[] args) 
    { 
     A a = null; 
     MethodInfo method = typeof(A).GetMethod("Method"); 
     OpenInstanceDelegate action = (OpenInstanceDelegate)Delegate.CreateDelegate(typeof(OpenInstanceDelegate), a, method); 

     PossiblyExecuteDelegate(action); 
    } 
} 
+0

Sì, come ho modificato la mia risposta, questo è possibile con la riflessione, ma non con il codice .NET compilato standard. La tua preoccupazione per il fatto che le persone ti passeranno sarà dichiaratamente delegata? –

1

Per fare ciò, è necessario passare un metodo static a PossiblyExecuteDelegate(). Questo ti darà un nullTarget.

class A 
{ 
    void Method(int a) {} 
    static void Method2(int a) {} 

    static void Main(string[] args) 
    { 
     PossiblyExecuteDelegate(A.Method2); 

     A a = new A(); 

     PossiblyExecuteDelegate(a.Method); 
    } 
} 

Edit: E è possibile passare un delegato ad un metodo di istanza senza bersaglio attraverso la riflessione, ma non utilizzando lo standard codice compilato.

+0

Voglio dire testare se il metodo di istanza verrebbe chiamato su un'istanza nulla, se è stato chiamato. Il problema è ottenere l'istanza in primo luogo. Ricordo di aver letto qualcosa sui delegati aperti, ma non riesco a trovare né pellame né capelli ora ... – thecoop

+0

Ho appena trovato i documenti di nuovo: puoi creare un delegato di istanze aperto usando un sovraccarico Delegate.CreateDelegate (ha postato una risposta con i dettagli) – thecoop

+0

@thecoop: Sì, avrei dovuto notare che ciò sarebbe stato possibile con la riflessione, ma non con un codice sicuro per la compilazione. Risposta modificata. –

0

E 'possibile con Delegate.CreateDelegate, esattamente con l'overload con la firma: CreateDelegate (Type, object, MethodInfo)

Se si specifica "null" per il secondo parametro (target) allora devi mettere un parametro aggiuntivo nel tipo delegato, che specifica il tipo di istanza, e wh it si invoca il delegato, l'istanza deve essere passata come primo argomento, seguita dai parametri "reali" del metodo.

class Test 
{ 
    public int AddStrings(string a, string b) 
    { 
     return int.Parse(a) + int.Parse(b); 
    } 

    static void Main() 
    { 
     var test = new Test(); 
     var methodInfo = test.GetType().GetMethod("AddStrings"); 
     // note the first extra parameter of the Func, is the owner type 
     var delegateType = typeof(Func<Test, string, string, int>); 
     var del = Delegate.CreateDelegate(delegateType, null, methodInfo); 

     var result = (int)del.DynamicInvoke(test, "39", "3"); 
    } 
} 
Problemi correlati