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

时间:2011-07-08 13:03:10

标签: c# function parameters anonymous-types

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

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

    }
}

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

10 个答案:

答案 0 :(得分:149)

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

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

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

答案 1 :(得分:37)

你可以这样做:

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

    }
}

...但你不会对每件物品做很多事情。你可以调用ToString,但是你不能直接使用{say} NameId

答案 2 :(得分:18)

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

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

struct Data {
  public string ColumnName; 
}

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

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

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

答案 3 :(得分:10)

除非参数类型为object,否则无法将匿名类型传递给非泛型函数。

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

    foreach (var item in list)
    {

    }
}

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

来自MSDN - Anonymous Types

  

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

(强调我的)


更新

您可以使用泛型来实现您想要的目标:

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

    }
}

答案 4 :(得分:7)

通常,您使用泛型来执行此操作,例如:

MapEntToObj<T>(IQueryable<T> query) {...}

然后,当您致电T时,编译器应推断MapEntToObj(query)。不太确定你想在方法中做什么,所以我不知道这是否有用......问题是在MapEntToObj里你仍然无法命名T - 你可以之一:

  • 使用T
  • 调用其他通用方法
  • 使用T上的反思来做事

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

另一个技巧(提取数据时)也是通过一个选择器 - 例如:

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

答案 5 :(得分:6)

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

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

答案 6 :(得分:6)

“dynamic”也可用于此目的。

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

   }
}

答案 7 :(得分:2)

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

  1. var dynamicResult = anonymousQueryResult.ToList<dynamic>();
  2. 方法签名:DoSomething(List<dynamic> _dynamicResult)
  3. 通话方式:DoSomething(dynamicResult);
  4. 进行。
  5. 感谢Petar Ivanov

答案 8 :(得分:0)

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

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

    }
}

答案 9 :(得分:0)

我会使用IEnumerable<object>作为参数的类型。然而,对于不可避免的明确演员来说,这并不是一个很大的好处 干杯