Comment passer des types anonymes comme paramètres?
Comment passer des types anonymes comme paramètres à d'autres fonctions? Prenons l'exemple suivant:
var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);
variable query
ici n'a pas de type fort. Comment définir ma fonction Log employees pour l'accepter?
public void LogEmployees (? list)
{
foreach (? item in list)
{
}
}
en d'autres termes, Que dois-je utiliser à la place des marques ?
.
10 réponses
je pense que vous devriez faire un cours 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 dynamique:
public void LogEmployees (IEnumerable<dynamic> list)
{
foreach (dynamic item in list)
{
string name = item.Name;
int id = item.Id;
}
}
notez que c'est pas fortement tapé, donc si, par exemple, le nom 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<T>(List<T> list) // Or IEnumerable<T> list
{
foreach (T item in list)
{
}
}
... mais vous n'obtiendrez pas beaucoup à faire avec chaque élément. Vous pouvez appeler ToString, 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 tapée pour être un IEnumerable d'un type anonyme. Les noms de type anonymes ne peuvent pas être représentés dans le code d'utilisateur, il n'y a donc aucun moyen de les transformer en paramètre d'entrée d'une fonction.
Votre meilleur pari est de créer un type et de l'utiliser comme retour de la requête, puis le passer à la fonction. Par exemple,
struct Data {
public string ColumnName;
}
var query = (from name in some.Table
select new Data { ColumnName = name });
MethodOp(query);
...
MethodOp(IEnumerable<Data> enumerable);
dans ce cas bien que vous ne sélectionniez qu'un seul champ, il peut donc être plus facile de le sélectionner directement. Ceci fera que la requête sera tapée comme un IEnumerable du type de champ. Dans ce cas, le nom de colonne.
var query = (from name in some.Table select name); // IEnumerable<string>
vous ne pouvez pas passer un type anonyme à une fonction non générique, à moins que le type de paramètre ne soit 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 le cadre d'une méthode.
à Partir de MSDN - Anonyme "Types de 151990920" :
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 une paramètre formel d'une méthode, une propriété, un constructeur, ou d'indexation comme ayant un type anonyme. pour passer un type anonyme, ou une collection qui contient des types anonymes, comme argument à une méthode, vous pouvez déclarer le paramètre comme objet type . Toutefois, cette opération ayant pour but de taper fort.
(l'emphase est mienne)
mise à Jour
Vous pouvez utiliser des génériques pour réaliser ce que vous voulez:
public void LogEmployees<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
}
}
normalement, vous faites cela avec des génériques, par exemple:
MapEntToObj<T>(IQueryable<T> query) {...}
le compilateur devrait alors inférer le T
quand vous appelez MapEntToObj(query)
. Pas tout à fait sûr de ce que vous voulez faire à l'intérieur de la méthode, donc je ne peux pas dire si c'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
- utilisation réflexion sur
T
faire des choses
mais à part cela, il est assez difficile de manipuler les types anonymes-notamment parce qu'ils sont immuables; - p
un autre truc (quand extraire données) est de passer aussi un sélecteur - i.e. quelque chose comme:
Foo<TSource, TValue>(IEnumerable<TSource> source,
Func<TSource,string> name) {
foreach(TSource item in source) Console.WriteLine(name(item));
}
...
Foo(query, x=>x.Title);
vous pouvez utiliser des génériques avec le truc suivant (casting au type anonyme):
public void LogEmployees<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
var typedItem = Cast(item, new { Name = "", Id = 0 });
// now you can use typedItem.Name, etc.
}
}
static T Cast<T>(object obj, T type)
{
return (T)obj;
}
"dynamique" 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<dynamic> anonymousTypes)
{
foreach (var info in anonymousTypes)
{
}
}
au lieu de passer un type anonyme, passer une liste d'un type dynamique:
-
var dynamicResult = anonymousQueryResult.ToList<dynamic>();
- méthode signature:
DoSomething(List<dynamic> _dynamicResult)
- méthode D'appel:
DoSomething(dynamicResult);
- fait.
merci à Petar Ivanov !
si vous savez que vos résultats implémentent une certaine interface, vous pouvez utiliser l'interface comme type de données:
public void LogEmployees<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
}
}
j'utiliserais IEnumerable<object>
comme type pour l'argument. Cependant pas un grand gain pour la distribution explicite inévitable.
Cheers