Domanda

Ho il seguente codice:

Func<string, bool> comparer = delegate(string value) {
    return value != "0";
};
.

Tuttavia, quanto segue non è compilato:

var comparer = delegate(string value) {
    return value != "0";
};
.

Perché il compilatore non può capire è un Func<string, bool>?Ci vuole un parametro di stringa e restituisce un booleano.Invece, mi dà l'errore:

.

non può assegnare un metodo anonimo a un variabile locale implicitamente digitata.

Ho un'ipotesi e cioè se la versione VAR compilata , mancherebbe la coerenza se avessi il seguente:

var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
    return false;
};
.

Quanto sopra non avrebbe senso dal momento che FUNC <> consente solo fino a 4 argomenti (in .NET 3.5, che è ciò che sto usando).Forse qualcuno potrebbe chiarire il problema.Grazie.

È stato utile?

Soluzione

Altri hanno già sottolineato che ci sono infiniti molti tipi di delegati possibili che potrebbero , hanno significato; Ciò che è così speciale del Func che merita di essere l'impostazione predefinita invece di Predicate o Action o qualsiasi altra possibilità? E, per Lambdas, perché è ovvio che l'intenzione è scegliere il modulo Delegato, piuttosto che il modulo dell'albero di espressione?

Ma potremmo dire che Func è speciale e che il tipo di inferno di un metodo Lambda o Anonymous è func di qualcosa. Avevamo ancora tutti i tipi di problemi. Quali tipi vorresti essere dedotto per i seguenti casi?

var x1 = (ref int y)=>123;
.

Non esiste un tipo Func<T> che prende un riferimento.

var x2 = y=>123;
.

Non conosciamo il tipo di parametro formale, anche se conosciamo il ritorno. (O noi siamo il ritorno int? Lungo? Breve? Byte?)

var x3 = (int y)=>null;
.

Non conosciamo il tipo di ritorno, ma non può essere vuoto. Il tipo di ritorno potrebbe essere qualsiasi tipo di riferimento o qualsiasi tipo di valore nullabile.

var x4 = (int y)=>{ throw new Exception(); }
.

Ancora una volta, non conosciamo il tipo di ritorno, e questa volta può essere vuoto.

var x5 = (int y)=> q += y;
.

È destinato ad essere una dichiarazione di ritorno voiding lambda o qualcosa che restituisce il valore assegnato a Q? Entrambi sono legali; che dovremmo scegliere?

Ora, potresti dire, bene, non supportare nessuna di queste funzionalità. Supporta i casi "normali" in cui i tipi possono essere risolti. Questo non aiuta. Come rende la mia vita più facile? Se la funzione funziona a volte e non riesce a volte, devo ancora scrivere il codice su rilevare tutte quelle situazioni di guasto e forniscono un messaggio di errore significativo significativo per ciascuno. Dobbiamo ancora specificare tutto quel comportamento, documentarlo, scrivere test per questo, e così via. Questa è una caratteristica molto costosa che salva l'utente forse una mezza dozzina di tasti. Abbiamo modi migliori per aggiungere valore alla lingua piuttosto che passare un sacco di tempo a scrivere casi di test per una funzione che non funziona metà del tempo e non fornisce quasi alcun beneficio nei casi in cui funziona.

La situazione in cui è effettivamente utile è:

var xAnon = (int y)=>new { Y = y };
.

Perché non c'è alcun tipo "parlabile" per quella cosa. Ma abbiamo questo problema tutto il tempo, e usiamo solo l'inferenza del tipo di metodo per dedurre il tipo:

Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });
.

E ora il tipo di inferenza del tipo funziona come è il tipo di func.

Altri suggerimenti

Solo Eric Lippert sa di sicuro, ma penso che sia perché la firma del tipo Delegate non determina in modo univoco il tipo.

Considera il tuo esempio:

var comparer = delegate(string value) { return value != "0"; };
.

Ecco due possibili inferenze per ciò che il var dovrebbe essere:

Predicate<string> comparer  = delegate(string value) { return value != "0"; };  // okay
Func<string, bool> comparer = delegate(string value) { return value != "0"; };  // also okay
.

Quale dovrebbe dedurre il compilatore?Non c'è una buona ragione per scegliere l'uno o l'altro.E sebbene un Predicate<T> sia funzionalmente equivalente a un Func<T, bool>, sono ancora diversi tipi a livello del sistema di tipo .NET.Il compilatore pertanto non può risolvere in modo non ambiguo risolvere il tipo di delegato e non è necessario fallire l'inferenza del tipo.

Eric Lippert ha un vecchio post a riguardo dove dice

.

E infatti la specifica C # 2.0 lo chiama fuori.Method Group. Espressioni e metodo anonimo Le espressioni sono espressioni tinta in c # 2.0, e le espressioni di lambda si uniscono loro in c # 3.0.Quindi è illegale per loro apparire "nudo" su il lato destro di un implicito Dichiarazione.

I diversi delegati sono considerati diversi tipi.ad es. Action è diverso da MethodInvoker e un'istanza di Action non può essere assegnata a una variabile di tipo MethodInvoker.

Quindi, dato un delegato anonimo (o lambda) come () => {}, è un Action o un MethodInvoker?Il compilatore non può dirlo.

Allo stesso modo, se dichiaro un tipo di delegato prendendo un argomento string e restituire un bool, come sarebbe il compilatore che si sa che hai davvero desiderato un Func<string, bool> invece del mio tipo di delegato?Non può dedurre il tipo di delegato.

I seguenti punti provengono dall'SDN per quanto riguarda le variabili locali digitate implicitamente digitate:

    .
  1. var può essere utilizzato solo quando una variabile locale è dichiarata e inizializzata nella stessa istruzione; La variabile non può essere inizializzata in null o a un gruppo di metodi o una funzione anonima.
  2. La parola chiave VAR incarica il compilatore di dedurre il tipo di variabile dall'espressione sul lato destro dell'istruzione di inizializzazione.
  3. È importante capire che la parola chiave var non significa "variante" e non indica che la variabile è esaurita, o legata in ritardo. Significa solo che il compilatore determina e assegna il tipo più appropriato.

    MSDN Riferimento: variabili locali digitate implicitamente

    Considerando quanto segue per quanto riguarda i metodi anonimi:

      .
    1. Metodi anonimi consentono di omettere l'elenco dei parametri.

      MSDN Riferimento: metodi anonimi

      Sospetto che dal momento che il metodo anonimo possa effettivamente avere firme di metodi diversi, il compilatore non è in grado di dedurre correttamente ciò che il tipo più appropriato da assegnare sarebbe.

Il mio post non risponde alla domanda reale, ma risponde alla domanda sottostante di:

"Come faccio a evitare di dover digitare un tipo FUGLY come Func<string, string, int, CustomInputType, bool, ReturnType>?" [1]

Essendo il programmatore pigro / hacky che sono, ho sperimentato con l'utilizzo di Func<dynamic, object> - che prende un singolo parametro di input e restituisce un oggetto.

Per più argomenti, puoi usarlo come:

dynamic myParams = new ExpandoObject();
myParams.arg0 = "whatever";
myParams.arg1 = 3;
Func<dynamic, object> y = (dynObj) =>
{
    return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite?
};
Console.WriteLine(y(myParams));
.

Suggerimento: è possibile utilizzare Action<dynamic> se non è necessario restituire un oggetto.

Sì, so che probabilmente va contro i principi di programmazione, ma questo ha senso per me e probabilmente alcuni codificatori Python.

Sono piuttosto novizio nei delegati ... volevo solo condividere ciò che ho imparato.


.

[1] Si presume che non si chiamano un metodo che richiede un Func predefinito come parametro, nel qual caso, dovrai digitare quella stringa FUGLY: /

Come è così?

var item = new
    {
        toolisn = 100,
        LangId = "ENG",
        toolPath = (Func<int, string, string>) delegate(int toolisn, string LangId)
        {
              var path = "/Content/Tool_" + toolisn + "_" + LangId + "/story.html";
              return File.Exists(Server.MapPath(path)) ? "<a style=\"vertical-align:super\" href=\"" + path + "\" target=\"_blank\">execute example</a> " : "";
        }
};

string result = item.toolPath(item.toolisn, item.LangId);
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top