2012-09-17 2 views
10

In un metodo di classe, A, ho bisogno di chiamare un metodo di libreria B, che prende come parametro IProgress<Object>.C# È possibile fornire un lambda quando è richiesta un'interfaccia?

Normalmente, potrei implementare IProgress<Object> come parte della classe in cui si trova A e quindi passare "questo" al metodo B. O forse potrei creare una nuova classe il cui unico scopo è implementare IProgress<Object> e gestirlo correttamente-- quindi in questo caso creerò un'istanza di quella classe e la passerò a B.

Ma quello che voglio veramente è che la mia implementazione di IProgress<Object> appaia proprio all'interno del metodo in cui sto chiamando B, quindi che c'è meno di una disconnessione visiva tra il codice chiamante e l'implementazione IProgress<Object>. (Considero la mia implementazione di IProgress come una sorta di dettaglio privato e non condiviso del metodo di chiamata e quindi non voglio che la mia implementazione di IProgress<Object> sia in un metodo completamente separato di forse un'intera altra classe).

Quello che ho cercato di fare è utilizzare un lambda in cui io definire la mia breve corso di movimentazione, e quindi in qualche modo passare questo lambda a B, in questo modo:

method in class A { 
... 
Action<Object> Report = (m) => { // do something useful with m }; 

B(Report) 
} 

method B(IProgress<Object> reporter) { 
    reporter.Report(some object) 
} 

Certo, lo so perché questo non funzionerà così com'è - B sta volendo un oggetto che implementa IProgress<Object> e sto passando un oggetto Azione invece.

C'è un modo per ottenere ciò che sto cercando di ottenere? (IE hanno mia implementazione se IProgress<Object> apparire all'interno metodo A?

+2

C# lambda sono delegati anonimi . Quello di cui hai bisogno è un tipo anonimo che implementa l'interfaccia. Vedi [questa domanda] (http://stackoverflow.com/questions/191013/can-a-c-sharp-anonymous-class-implement-an-interface) per alcune soluzioni alternative rispetto ai soli tipi anonimi di proprietà pubbliche forniti da C#. –

risposta

11

I delegati non possono implementare le interfacce (direttamente).

due buone opzioni vengono in mente:

  1. cambiare la definizione del metodo che si sta chiamando a prendere un tipo delegato invece di un tipo IProgress. (Se possibile, questa sarebbe l'opzione preferibile)

  2. Creare un nuovo tipo che implementa l'interfaccia necessaria e accetta un delegato come parametro per implementare tale funzionalità.

E l'esempio di # 2, mentre dipende l'interfaccia, potrebbe essere simile a questa:

interface IProgress<T> 
{ 
    void doStuff(T param); 
} 

class LambdaProgress<T> : IProgress<T> 
{ 
    Action<T> action; 
    public LambdaProgress(Action<T> action) 
    { 
     this.action = action; 
    } 

    public void doStuff(T param) 
    { 
     action(param); 
    } 
} 

allora si sarebbe in grado di fare qualcosa di simile:

B(new LambdaProgress<Object>(obj => ...)); 
1

Supponendo che l'interfaccia IProgress<object> ha appena il solo metodo void Report(object), e che si controlla l'API, si potrebbe semplicemente ridefinire i metodi che attualmente richiedono un parametro di tipo IProgress<object> a invece richiedono un nuovo tipo delegato:

public delegate void ProgressReportDelegate(object someObject); 

Poi il tuo esempio potrebbe cambiare a:

method in class A { 
... 
Action<Object> Report = (m) => { // do something useful with m }; 

B(Report) 
} 

method B(ProgressReportDelegate reporter) { 
    reporter(someObject); 
} 

per le interfacce più complesse, o dove non si controlla l'API (e quindi non si può cambiare un metodo per assumere il delegato anziché l'oggetto che implementa quell'interfaccia), questa non è realmente un'opzione, ma sembrerebbe funzionare nel tuo caso.

4

No, non puoi fornire un lambda quando è richiesta un'interfaccia.
Ma è possibile fornire un oggetto anonimo utilizzando impromptu-interface.

Questo esempio è dalla sua pagina del progetto:

//Anonymous Class 
var anon = new 
{ 
    Prop1 = "Test", 
    Prop2 = 42L, 
    Prop3 = Guid.NewGuid(), 
    Meth1 = Return<bool>.Arguments<int>(it => it > 5) 
} 

var myInterface = anon.ActLike<IMyInterface>(); 

Nel tuo esempio questo può essere:

A 
{ 
    // Create an anonymous object. 
    var anonymous = new 
    { 
     // Define a method that needs an "object" parameter and returns nothing. 
     Report = Return.Arguments<object>(m => 
     { 
      // Do whatever you want to do when Report is called. 
     }) 
    } 

    // Get your anonymous object as an IProgress<Object>. 
    var obj = anonymous.ActLike<IProgress<Object>> 

    // Call B. 
    B(obj); 
} 
0

Con .NET 4.5 è possibile utilizzare Progress classe