Domanda

So che non puoi restituire tipi anonimi dai metodi, ma mi chiedo come il metodo di estensione Select restituisca un tipo anonimo. È solo un trucco da compilatore?

Modifica

Supponiamo che L sia un elenco. Come funziona?

L.Select(s => new { Name = s })

Il tipo restituito è IEnumerable < 'a > dove 'a = new {String Name}

È stato utile?

Soluzione

Il tipo è in realtà definito da il chiamante , quindi rientra nell'ambito della funzione di chiamata - evitando ordinatamente il problema di " restituendo " un tipo anonimo.

Ciò è ottenuto dall'inferenza di tipo generico. La firma per Select è Select<Tsource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>. IEnumerable<TSource> è, ovviamente, la raccolta di origine. La funzione di trasformazione Func<Tsource, TResult> è dove il compilatore può usare l'inferenza di tipo per dichiarare un tipo anonimo.

In altre parole, per passare da Select a TResult, tu, il chiamante, devi definire <=>. Il che significa che <=> non sta restituendo un tipo anonimo definito da esso, ma da te.

Per emulare questo, devi solo convincere il chiamante a definire il tipo:

TResult ReturnAnonymousType<TResult>(Func<TResult> f) {
   return f();
}

Console.WriteLine(ReturnAnonymousType(
   () => return new { Text = "Hello World!" } // type defined here, before calling 
);

Altri suggerimenti

Bene, è normale inferenza di tipo per argomenti di tipo metodo generico. Ad esempio:

List<string> x = new List<string>();

// The compiler converts this:
x.Select(y => y.Length);

// Into this, using type inference:
Enumerable.Select<string, int>(x, y => y.Length);

Lo stesso sarebbe vero se x fosse un elenco di un tipo anonimo o se il tipo di ritorno inferito dell'espressione lambda fosse un tipo anonimo. Non dimenticare che anche se non puoi dichiarare esplicitamente il tipo di una variabile che utilizza un tipo anonimo, ha un tipo definito, noto al compilatore.

Dal commento: " Quindi, come farei per implementare un metodo simile & Quot;

Tutto ciò che serve qui è un metodo generico:

public List<T> Foo<T>(T template) { // doesn't actually use "template"
    return new List<T>();  // just an example
}

allora puoi avere:

var list = Foo(new {Bar=1});

Il compilatore fornisce <T> tramite inferenza di tipo generico.

Un po 'sfacciato, ma puoi persino farlo senza mai creare un'istanza del tipo anon:

public List<T> Foo<T>(Func<T> func) { // doesn't actually use "func"
    return new List<T>(); // just an example
}

var list = Foo(() => new {Bar = 1});

Anche in questo caso, viene fornito dal compilatore tramite il valore restituito da lambda.

Il tipo restituito di Select è generico ed è dedotto dalla lambda fornita nella maggior parte delle situazioni.

Ad esempio:

List<int> list = new List<int<();

var val = list.Select(x => new {value = x, mod = x % 10});

Il valore di ritorno della selezione si basa sul tipo anonimo che ho definito ed è estrapolato dalla funzione lambda, a un delegato, alla funzione Seleziona. La funzione Seleziona in questo caso non è a conoscenza o si preoccupa del particolare tipo anonimo, poiché è un tipo generico dal suo punto di vista.

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