使用C#匿名类型

时间:2010-10-14 17:14:52

标签: c# dynamic .net-4.0 anonymous-types

我正在调用一个返回包含c#Anonymous Type对象的List变量的方法。例如:

List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
    list.Add( new {
        ContactID = c.ContactID,
        FullName = c.FullName
    });
}
return list;

如何在我正在处理的代码中引用此类型属性,例如

foreach ( object o in list ) {
    Console.WriteLine( o.ContactID );
}

我知道我的样本是不可能的,我只是这样说,我需要确切地识别匿名类型的每个属性。

谢谢!

解决方案

其中一个答案是正确的和/或建议一个有效的解决方案。我最终使用了Greg选项3的答案。我在.NET 4.0中学到了dynamic非常有趣的东西!

8 个答案:

答案 0 :(得分:35)

您无法返回匿名类型的列表,它必须是object的列表。因此,您将丢失类型信息。

选项1
不要使用匿名类型。如果您尝试在多个方法中使用匿名类型,则创建一个真正的类。

选项2
不要将您的匿名类型转发为object。 (必须采用一种方法)

var list = allContacts
             .Select(c => new { c.ContactID, c.FullName })
             .ToList();

foreach (var o in list) {
    Console.WriteLine(o.ContactID);
}

选项3
使用dynamic关键字。 (需要.NET 4)

foreach (dynamic o in list) {
    Console.WriteLine(o.ContactID);
}

选项4
使用一些肮脏的反射。

答案 1 :(得分:4)

foreach ( var o in list ) {
    Console.WriteLine( o.ContactID );
}

仅当列表为IEnumerable<anonymous type>时才会起作用,如下所示:

var list = allContacts.Select(c => new {
        ContactID = c.ContactID,
        FullName = c.FullName
    });
}

但是你不能返回匿名类型,因为你必须定义返回类型(你不能返回var)并且匿名类型不能有名字。你应该创建非匿名类型,如果你要传递它。实际上,除了查询内部之外,不应该使用过多的匿名类型。

答案 2 :(得分:2)

如果你有这样的方法:

  List<object> GetContactInfo() {
    List<object> list = new List<object>();
    foreach ( Contact c in allContacts ) { 
        list.Add( new { 
            ContactID = c.ContactID, 
            FullName = c.FullName 
        }); 
    } 
    return list;
  }

你不应该这样做,但你可以使用very ugly and not future-proof技术:

  static T CastByExample<T>(object target, T example) {
    return (T)target;
  } 

  // .....

  var example = new { ContactID = 0, FullName = "" };
  foreach (var o in GetContactInfo()) {
    var c = CastByExample(o, example);
    Console.WriteLine(c.ContactID);
  }

它依赖于事实(可以改变!)编译器为具有相同“形状”(属性名称和类型)的类型重用匿名类型。由于您的“示例”与方法中类型的“形状”匹配,因此重复使用相同的类型。

C#4中的动态变量是解决此问题的最佳方法。

答案 3 :(得分:1)

您无法使用匿名类型执行此操作。只需创建一个Contact类/结构并使用它。

List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
    list.Add( c );
}

然后你可以这样做:

foreach ( var o in list ) {
    Console.WriteLine( o.ContactID );
}

......或者这个:

foreach ( object o in list ) {
    Console.WriteLine( ((Contact)o).ContactID ); //Gives intellisense
}

当然,在这种情况下,您应该创建一个联系人列表而不是对象列表:

List<Contact> list = new List<Contact>();
foreach ( Contact c in allContacts ) {
    list.Add( c );
}

编辑:错过了问题的基本部分。现在修好了。
编辑:再次更改答案。见上文。

答案 4 :(得分:0)

用每个构造的var in替换object可以起作用

答案 5 :(得分:0)

我知道我迟到了,但是我正在研究其他事情,发现这个article可以回答你的问题。

可以将对象列表强制转换为匿名类型。

    public static void Main()
    {
        foreach (object item in GetList())
        {
            var x = Cast(item, new { ContactID = 0, FullName = "" });
            Console.WriteLine(x.ContactID + " " + x.FullName);
        }

    }

    public static IEnumerable<object> GetList()
    {
        yield return new { ContactID = 4, FullName = "Jack Smith" };
        yield return new { ContactID = 5, FullName = "John Doe" };
    }

    public static T Cast<T>(object obj, T type)
    {
        return (T)obj;
    }

答案 6 :(得分:0)

列出回来

public static void Main()
{
    foreach (object item in GetList())
    {
        var x = Cast(item, new { ContactID = 0, FullName = "" });
        Console.WriteLine(x.ContactID + " " + x.FullName);
    }

}

public static IEnumerable<object> GetList()
{
    yield return new { ContactID = 4, FullName = "Jack Smith" };
    yield return new { ContactID = 5, FullName = "John Doe" };
}

public static T Cast<T>(object obj, T type)
{
    return (T)obj;
}

答案 7 :(得分:-1)

我会用

allContacts
 .Select(c => new { c.ContactID, c.FullName })
 .ToList()
 .ForEach(c => {
   ...do stuff;
 });

然后你根本不需要申报。 我相信减少声明,减少分号导致更少的bug