2012-03-07 12 views
13

Ho due metodi derivazione a IDataReader con i seguenti identificativi:Conversione di un metodo gruppo interno a un delegato con un tipo generico

internal static List<T> GetList<T>(this IDataReader reader, Func<string, T> del) 

internal static double? GetDoubleOrNull(this IDataReader reader, string columnName) 

GetDoubleOrNull non ha alcuna sovraccarichi.

Altrove, sono in grado di fare

Func<string, double?> del = reader.GetDoubleOrNull; 

var x = reader.GetList(del); 

o

var x = reader.GetList<double?>(reader.GetDoubleOrNull); 

o semplicemente passare un metodo di istanza come

public double? blah(string s) 

var x = reader.GetList(blah); 

ma non posso fare

var x = reader.GetList(reader.GetDoubleOrNull); 

Il compilatore dà l'errore

cannot convert from 'method group' to 'System.Func<string,double?>' 

Non capisco questo. Ho pensato che poiché non c'è sovraccarico su GetDoubleOrNull, non ci sarebbe una risoluzione di sovraccarico e potrebbe dedurre il parametro di tipo dalla firma del metodo.

La parte davvero confusa è come sembra funzionare quando si passa in blah.

+3

Molto interessante. Un cast esplicito '' var x = reader.GetList ((Func ) Reader.GetDoubleOrNull) '' Funziona anche. Il ricercatore contrassegna il cast come ridondante, ma senza di esso la compilazione fallisce. Jon Skeet è in giro? –

+3

C'è un modo per invocare Jon Skeet (o forse Eric Lippert)? Dì il loro nome tre volte o qualcosa del genere? – Chris

+1

correlati: http://stackoverflow.com/questions/7745852/method-inference-does-not-work-with-method-group e http://stackoverflow.com/questions/2057146/compiler-ambiguous-invocation-error -anonymous-method-and-method-group-with-fun – AakashM

risposta

0

GetDoubleOrNull restituisce un doppio? GetList aspetta un IDataReader e un System.Func<string,int?>

Il messaggio di errore è un po 'fuorviante

doppia pubblico? blah (string s)

var x = reader.GetList (blah);

blah è un delegato in questa chiamata. In GetList (GetDoubleOrNull) è il risultato di ottenere doubleOrNull.

Buona domanda però. Pubblica la risposta che ho aiutato o no.

+0

Il '' int'' deve essere un refuso, cambiarlo in '' double'' dà comunque l'errore del compilatore. –

+0

Jacek è corretto. Errore mio. Scusate. – Moss

+1

Hai detto "In GetList (GetDoubleOrNull) è il risultato di ottenere doubleOrNull" ma non è giusto. In questo caso 'GetDoubleOrNull' non viene valutato, viene trattato come un gruppo di metodi. – Chris

8

Prefazione: consente di passare alla modifica se si desidera la spiegazione completa. Spoiler: I metodi di estensione sono un trucco del compilatore e in realtà hanno un argomento in più di quello che sembrano quando li invochi.

È nella risoluzione del gruppo metodo. Apparentemente il compilatore C# non impiega il tempo per capire se il metodo che si sta usando ha sovraccarichi o meno; richiede sempre un cast esplicito. Partenza:

What is a method group in C#?
Method Inference does not work with method group

Il gruppo metodo che torna da reader.GetDoubleOrNull è limitato giù da quello che si tenta di lanciare a: GetDoubleOrNull potrebbe riferirsi a qualsiasi numero di metodi di overload con quel nome. Devi castarlo esplicitamente.

È interessante notare che non si può nemmeno assegnare un gruppo di metodo per una variabile implicitamente tipizzate per lo stesso motivo:

var x = reader.GetDoubleOrNull; 

fallisce la compilazione perché richiede un cast esplicito.

Edit Sono abbastanza sicuro che la confusione qui ha a che fare con i metodi di estensione:

controllare il seguente classe di test:

public static class Extensions 
{ 
    public static List<T> GetList<T>(this IDataReader reader, Func<string, T> del) 
    { 
     throw new NotImplementedException(); 
    } 

    public static double? GetDoubleOrNull(this IDataReader reader, string columnName) 
    { 
     throw new NotImplementedException(); 
    } 

    public static double? blah(this string s) 
    { 
     throw new NotImplementedException(); 
    } 
} 

È possibile chiamare con successo

var x = reader.GetList(Extensions.blah); 

Perché questo potrebbe essere? blah è anche un metodo di estensione statica, quindi, in base alle prove, sembrerebbe che la riga precedente non debba essere compilata. A complicare ulteriormente le cose, aggiungiamo questo metodo:

public static List<T> GetList2<T>(this IDataReader reader, Func<IDataReader, string, T> del) 
{ 
    throw new NotImplementedException(); 
} 

È ora possibile chiamare

x = reader.GetList2(Extensions.GetDoubleOrNull); 

e sarà compilato correttamente. Cosa dà?

Ecco la risposta: Metodi di estensione non in realtà aggiungere metodi ai propri oggetti. Sono davvero un trucco per il compilatore che ti permette di programmare come se quei metodi facessero parte delle tue classi. Da here:

Nel codice si richiama il metodo di estensione con metodo istanza sintassi. Tuttavia, il linguaggio intermedio (IL) generato dal compilatore converte il codice in una chiamata sul metodo statico. Pertanto, il principio di incapsulamento non viene realmente violato . In effetti, i metodi di estensione non possono accedere alle variabili private nel tipo che stanno estendendo.

Così, quando si chiama

var x = reader.GetDoubleOrNull("myColumnName"); 

ciò che viene effettivamente compilato ed eseguito è essenzialmente questo (una chiamata perfettamente legittima, anche se è un metodo di estensione):

var x = Extensions.GetDoubleOrNull(reader, "myColumnName"); 

Così , quando si tenta di utilizzare GetDoubleOrNull come argomento per un Func<string, double?>, il compilatore sta andando "Posso trasformare GetDoubleOrNull in un Func<IDataReader, string, double?> perché ha due argomenti, ma io non k ora come trasformarlo in un Func<string, double?> "

Anche se si sta chiamando come se si tratta di un metodo di IDataReader con una sola arg esempio, non è: è solo un metodo statico con due argomenti che il C# il compilatore ti ha indotto a pensare è parte di IDataReader.

+0

Ottima risposta e ricerca. Voglio fare +1 di nuovo. ;-) – Chris

+3

Non sono Jon Skeet, ma faccio quello che posso: D – eouw0o83hf

+0

Grazie per la risposta. Purtroppo ancora non mi sembra di capire chiaramente il problema. La prima domanda a cui si fa riferimento è una di cui sono a conoscenza. Ho letto il secondo, oltre a quelli pubblicati da AakashM, e mi sembra che dipenda da come la risoluzione del sovraccarico non tiene conto dei tipi di ritorno. Lo capisco. Ma come, quindi, passare in 'blah' lavoro? Non c'è una risoluzione di sovraccarico che si verifica in quel caso? Se no, perché no? Se è così, come è che ha successo? – Moss

Problemi correlati