Comment passer des types anonymes en tant que parameters?

Comment puis-je transmettre des types anonymes en tant que parameters à d’autres fonctions? Considérez cet exemple:

var query = from employee in employees select new { Name = employee.Name, Id = employee.Id }; LogEmployees(query); 

La query variable ici n’a pas de type fort. Comment définir ma fonction LogEmployees pour l’accepter?

 public void LogEmployees (? list) { foreach (? item in list) { } } 

En d’autres termes, que dois-je utiliser à la place de ? des notes.

Je pense que vous devriez faire une classe pour ce type anonyme. Ce serait la chose la plus sensée à faire à mon avis. Mais si vous ne voulez vraiment pas, vous pouvez utiliser la dynamic:

 public void LogEmployees (IEnumerable list) { foreach (dynamic item in list) { ssortingng name = item.Name; int id = item.Id; } } 

Notez que ceci n’est pas fortement typé, donc si, par exemple, Name change en EmployeeName, vous ne saurez pas qu’il y a un problème jusqu’à l’exécution.

Vous pouvez le faire comme ceci:

 public void LogEmployees(List list) // Or IEnumerable list { foreach (T item in list) { } } 

… mais vous ne ferez pas grand chose avec chaque article. Vous pourriez appeler ToSsortingng, mais vous ne pourrez pas utiliser (dire) Name et Id directement.

Malheureusement, ce que vous essayez de faire est impossible. Sous le capot, la variable de requête est typée IEnumerable d’un type anonyme. Les noms de types anonymes ne peuvent pas être représentés dans le code utilisateur, il est donc impossible de les transformer en paramètre d’entrée pour une fonction.

Votre meilleur pari est de créer un type et de l’utiliser comme retour à partir de la requête, puis de le transmettre à la fonction. Par exemple,

 struct Data { public ssortingng ColumnName; } var query = (from name in some.Table select new Data { ColumnName = name }); MethodOp(query); ... MethodOp(IEnumerable enumerable); 

Dans ce cas, cependant, vous ne sélectionnez qu’un seul champ, il est donc plus facile de sélectionner le champ directement. Cela provoquera la saisie de la requête en tant que IEnumerable du type de champ. Dans ce cas, nom de la colonne.

 var query = (from name in some.Table select name); // IEnumerable 

Vous ne pouvez pas passer un type anonyme à une fonction non générique, sauf si le type de paramètre est object .

 public void LogEmployees (object obj) { var list = obj as IEnumerable(); if (list == null) return; foreach (var item in list) { } } 

Les types anonymes sont destinés à une utilisation à court terme dans une méthode.

De MSDN – Types anonymes :

Vous ne pouvez pas déclarer un champ, une propriété, un événement ou le type de retour d’une méthode comme ayant un type anonyme. De même, vous ne pouvez pas déclarer un paramètre formel d’une méthode, d’une propriété, d’un constructeur ou d’un indexeur comme ayant un type anonyme. Pour transmettre un type anonyme ou une collection contenant des types anonymes en tant qu’argument à une méthode, vous pouvez déclarer le paramètre en tant qu’object type . Cependant, cela va à l’encontre du but d’un typage fort.

(emphase le mien)


Mettre à jour

Vous pouvez utiliser des génériques pour obtenir ce que vous voulez:

 public void LogEmployees(IEnumerable list) { foreach (T item in list) { } } 

Normalement, vous faites cela avec des génériques, par exemple:

 MapEntToObj(IQueryable query) {...} 

Le compilateur doit alors déduire le T lorsque vous appelez MapEntToObj(query) . Je ne suis pas sûr de ce que vous voulez faire dans la méthode, donc je ne peux pas dire si cela est utile … le problème est que dans MapEntToObj vous ne pouvez toujours pas nommer le T – vous pouvez soit:

  • appeler d’autres méthodes génériques avec T
  • utiliser la reflection sur T pour faire les choses

mais à part cela, il est assez difficile de manipuler des types anonymes – notamment parce qu’ils sont immuables ;-p

Une autre astuce (lors de l’ extraction de données) consiste également à passer un sélecteur, c’est-à-dire quelque chose comme:

 Foo(IEnumerable source, Func name) { foreach(TSource item in source) Console.WriteLine(name(item)); } ... Foo(query, x=>x.Title); 

Vous pouvez utiliser des génériques avec l’astuce suivante (conversion de type anonyme):

 public void LogEmployees(IEnumerable list) { foreach (T item in list) { var typedItem = Cast(item, new { Name = "", Id = 0 }); // now you can use typedItem.Name, etc. } } static T Cast(object obj, T type) { return (T)obj; } 

“dynamic” peut également être utilisé à cette fin.

 var anonymousType = new { Id = 1, Name = "A" }; var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" }; private void DisplayAnonymousType(dynamic anonymousType) { } private void DisplayAnonymousTypes(IEnumerable anonymousTypes) { foreach (var info in anonymousTypes) { } } 

Au lieu de passer un type anonyme, transmettez une liste de type dynamic:

  1. var dynamicResult = anonymousQueryResult.ToList();
  2. Signature de méthode: DoSomething(List _dynamicResult)
  3. Méthode d’appel: DoSomething(dynamicResult);
  4. terminé.

Merci à Petar Ivanov !

Si vous savez que vos résultats implémentent une certaine interface, vous pouvez utiliser l’interface en tant que type de données:

 public void LogEmployees(IEnumerable list) { foreach (T item in list) { } } 

J’utiliserais IEnumerable comme type pour l’argument. Cependant, pas un grand gain pour l’inévitable casting explicite. À votre santé