2011-11-08 4 views
9

Ho un metodo che accetta un'istanza Expression<Func<T, object>>. Voglio ottenere il tipo di dati effettivo restituito da un'istanza di espressione specifica, anziché da object.Ottieni il tipo di ritorno effettivo da un'espressione <Func <T, object>> istanza

Posso farlo funzionare per riferimenti diretti di proprietà, quindi se passo nell'espressione x => x.IntegerProperty posso ottenere un riferimento Tipo per un numero intero. Questo approccio richiede la sua conversione in MemberExpression.

Tuttavia, non riesco a farlo funzionare per espressioni arbitrarie. Ad esempio, se l'espressione è x => x.IntegerProperty.ToString(), desidero ottenere un riferimento Tipo per una stringa. Non riesco a compilarlo a un MemberExpression, e se ho solo .Compile() e controllare il tipo di ritorno ottengo "oggetto".

Come è possibile esaminare l'istanza dell'espressione specifica e derivare il tipo di reso effettivo?

+0

Tecnicamente, il tipo di ritorno effettivo dell'espressione è ... 'oggetto'. Poiché la funzione era necessaria per restituire 'object', sono state generate le espressioni necessarie per garantire che sia il tipo restituito (una conversione in questo caso). –

risposta

17

Qualcosa come questo potrebbe fare il trucco. Probabilmente non copre tutte le possibilità, ma è un inizio.

+0

Non riuscivo a pensare a nessun altro tipo di espressione che potesse essere se non fosse effettivamente 'object'. Copre tutti i casi che potrei pensare. –

+0

Ha funzionato alla grande. Sto usando questo in un insieme piuttosto specifico di circostanze, quindi se ci sono casi limite che non hai coperto non mi stanno ancora causando alcun dolore. Grazie! –

+0

Non è expr.Body.Type abbastanza? Ottengo risultati errati quando utilizzo il codice sopra con ad esempio i => (float) i dove è un intero. Quindi questo codice restituisce un numero intero e non mobile. Ma semplicemente expr.Body.Type funziona. –

2

Anche se non impossibile, questo è particolarmente difficile. Richiederebbe di camminare sull'albero delle espressioni e fare una logica potenzialmente complessa. Ad esempio, cosa vorresti vedere se passassi nell'espressione seguente?

Func<bool, object> expr = switch => switch ? 1 : "False"; 

Questo metodo potrebbe o restituire un int o una string.

Ora, potresti essere in grado di fare ulteriori progressi scaricando parte di questa logica sul compilatore. È possibile modificare il parametro del metodo da Func<T, object> a Func<T, TReturn> e utilizzare typeof(TReturn) all'interno del metodo per determinare cosa il compilatore ha deciso che fosse il tipo di ritorno dell'espressione.

Naturalmente, nel caso del mio esempio, lavorerete ancora contro object. Ma il tuo esempio di x => x.IntegerProperty.ToString() produrrà string, che è quello che stai cercando.

+0

Si ottengono alcuni buoni punti, ma questo viene utilizzato in alcune circostanze specifiche in cui i casi limite non dovrebbero venire scoperti (o possono essere facilmente evitati conoscendoli). Grazie! –

+2

In realtà, @Adam Maras, l'esempio non verrà mai compilato nemmeno perché l'operatore ternario genera un errore in fase di compilazione che dice "Impossibile determinare il tipo di espressione condizionale perché non c'è conversione implicita tra" int "e" stringa "" –

+0

era più un esercizio di pensiero che un esempio di codice letterale. –

0

po 'di un modo sfacciato (e si tratta in realtà invocando la Func), ma si può fare questo:

using System; 

class Program 
{ 
    static Func<T,object> MakeFunc<T>() 
    { 
     return x => 23; 
    } 

    static Type GetReturnType<T>(Func<T,object> f) 
    { 
     return f(default(T)).GetType(); 
    } 

    static void Main(string[] args) 
    { 
     Type t = GetReturnType(MakeFunc<string>()); 
     Console.WriteLine(t); 
    } 
} 

Non è garantito il funzionamento in tutte le situazioni, devo aggiungere - in particolare se l'isn default(T) 'un parametro valido per Func. Ma è un potenziale punto di partenza almeno.

+2

Non sono sicuro di come mi sento nell'eseguire l'espressione per ottenere il tipo restituito; cosa succede se ci sono effetti collaterali alla funzione?Nel mio caso specifico non è una grande preoccupazione, ma ho accettato una risposta che sembra funzionare altrettanto bene e non richiede l'esecuzione. Grazie comunque! –

+0

@Seth: Personalmente non sarei troppo felice di eseguire l'espressione (si tratta di una limitazione del metodo) - era solo il meglio che potevo venire con la parte superiore della mia testa. L'unico vantaggio di questo approccio è che funziona su istanze 'Func' piuttosto che su istanze di' Expression'. –