如何将匿名类型作为参数传递?

如何将匿名类型作为参数传递给其他函数? 考虑这个例子:

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

这里的变量query没有强类型。 我应该如何定义我的LogEmployees函数来接受它?

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

换句话说,我应该使用什么而不是? 分数。

我认为你应该为这个匿名类型创建一个类。 在我看来,那是最明智的做法。 但如果你真的不想,你可以使用动力学:

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

请注意,这不是强类型的,因此,例如,如果名称更改为EmployeeName,则在运行时之前您不会知道存在问题。

你可以这样做:

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

……但是你不会对每件物品做很多事情。 你可以调用ToString,但你不能直接使用(比如) NameId

不幸的是,你想做的事情是不可能的。 在引擎盖下,查询变量被键入为匿名类型的IEnumerable。 匿名类型名称无法在用户代码中表示,因此无法使它们成为函数的输入参数。

最好的办法是创建一个类型并将其用作查询的返回值,然后将其传递给函数。 例如,

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

但在这种情况下,您只选择一个字段,因此直接选择字段可能更容易。 这将导致查询被键入为字段类型的IEnumerable。 在这种情况下,列名称。

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

除非参数类型是object ,否则不能将匿名类型传递给非generics函数。

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

匿名类型旨在用于方法中的短期使用。

来自MSDN – 匿名类型 :

您不能将方法的字段,属性,事件或返回类型声明为具有匿名类型。 同样,您不能将方法,属性,构造函数或索引器的forms参数声明为具有匿名类型。 要将匿名类型或包含匿名类型的集合作为方法的参数传递,可以将参数声明为类型对象 。 但是,这样做会破坏强类型的目的。

(强调我的)


更新

您可以使用generics来实现您想要的:

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

通常,您使用generics执行此操作,例如:

 MapEntToObj(IQueryable query) {...} 

然后,当您调用MapEntToObj(query)时,编译器应该推断出T 不太确定你想在方法内做什么,所以我不知道这是否有用……问题是在MapEntToObj你仍然无法命名T – 你可以:

  • T调用其他generics方法
  • Treflection来做事

但除此之外,操纵匿名类型是相当困难的 – 尤其是因为它们是不可变的;-p

另一个技巧( 提取数据时)也是传递选择器 – 例如:

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

您可以使用generics与以下技巧(强制转换为匿名类型):

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

“动态”也可用于此目的。

 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) { } } 

不传递匿名类型,而是传递动态类型的List:

  1. var dynamicResult = anonymousQueryResult.ToList();
  2. 方法签名: DoSomething(List _dynamicResult)
  3. 调用方法: DoSomething(dynamicResult);
  4. 完成。

感谢Petar Ivanov !

如果您知道,您的结果实现了某个接口,您可以使用该接口作为数据类型:

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

我会使用IEnumerable作为参数的类型。 然而,对于不可避免的明确演员而言,这并不是一个巨大的收获 干杯