2008-11-28 13 views
4

Je sais que vous ne pouvez pas retourner les types anonymes des méthodes mais je me demande comment la méthode d'extension Select renvoie un type anonyme. Est-ce juste un truc de compilateur?Méthodes et types anonymes

Modifier

Supposons que L est une liste. Comment cela marche-t-il?

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

Le type de retour est IEnumerable < 'a> où' a = new {String Name}

Répondre

8

Le type est en fait défini par l'appelant, donc c'est dans le cadre de la fonction d'appel - en évitant soigneusement le problème de "renvoyer" un type anonyme.

Ceci est accompli par l'inférence de type générique. La signature pour Select est Select<Tsource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>. Le IEnumerable<TSource> est, évidemment, la collection source. La fonction de transformation Func<Tsource, TResult> est l'endroit où le compilateur peut utiliser l'inférence de type pour déclarer un type anonyme. En d'autres termes, pour passer un Func<Tsource, TResult> à Select, vous devez définir l'appelant TResult.Ce qui signifie Select ne renvoie pas un type anonyme défini par lui - mais par vous.

Pour imiter cela, il vous suffit d'obtenir l'appelant pour définir le type:

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

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

Eh bien, il est l'inférence de type normal pour les arguments de type méthode générique. Par exemple:

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); 

Le même serait vrai si x étaient une liste d'un certain type anonyme, ou si le type de retour inférée de l'expression lambda était un type anonyme. N'oubliez pas que même si vous ne pouvez pas indiquer explicitement le type d'une variable qui utilise un type anonyme, a toujours un type défini, connu du compilateur.

+0

En fait, vous pouvez même avoir une liste des types anonymes? Je pense qu'il parlait de quand, au lieu de int, vous avez un type anonyme dans votre exemple. – Guvante

+0

Oui, vous pouvez facilement avoir une liste avec un élément de type anonyme: new [] {new {Name = "Jon"}} .ToList(); –

+0

Il existe également d'autres moyens d'obtenir des listes - par exemple, en écrivant une méthode d'extension et en utilisant une seule instance anon (ou un lambda à un) pour transformer un T en Liste

1

Le type de retour de Select est générique, et il est déduit du lambda fourni dans la plupart des situations.

Par exemple:

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

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

La valeur de retour de la sélection est basée sur le type anonyme je définissais, et est extrapolée à partir du lambda, à un délégué, à la fonction Select. La fonction Select dans ce cas ne connaît pas ou ne se soucie pas du type anonyme particulier, car il s'agit d'un type générique de son point de vue.

+0

Merci Guvante. Alors, comment pourrais-je mettre en œuvre une méthode similaire? –

5

De commentaire: "Alors, comment pourrais-je aller sur la mise en œuvre d'une méthode similaire"

Tout ce que vous avez besoin ici est une méthode générique:

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

alors vous pouvez avoir:

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

Le compilateur fournit le <T> via l'inférence de type générique.

Un peu culotté, mais vous pouvez même le faire sans actaully jamais créer une instance du type 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}); 

Encore une fois, est fourni par le compilateur via la valeur de retour du lambda.

Questions connexes