使用 C# 匿名类型

发布于 2024-09-27 11:24:04 字数 583 浏览 0 评论 0原文

我正在调用一个返回包含 ac# 匿名类型对象的列表变量的方法。例如:

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 中的动态的非常有趣的事情!

I am calling a method that returns a List variable that contains a c# Anonymous Type objects. For example:

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

How do I reference this type properties in the code I am working on like for example

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

I know that my sample is not possible, I have only wrote that way to say that I need to identify each property of the anonymous type exactly.

Thanks!

Solution:

Not just one of the answer is correct and/or suggest a working solution. I have ended up to using Option 3 of Greg answer. And I learned something very interesting regarding the dynamic in .NET 4.0!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

徒留西风 2024-10-04 11:24:04

您不能返回匿名类型的列表,它必须是对象的列表。因此您将丢失类型信息。

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

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

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

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

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

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

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

You can't return a list of an anonymous type, it will have to be a list of object. Thus you will lose the type information.

Option 1
Don't use an anonymous type. If you are trying to use an anonymous type in more than one method, then create a real class.

Option 2
Don't downcast your anonymous type to object. (must be in one method)

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

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

Option 3
Use the dynamic keyword. (.NET 4 required)

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

Option 4
Use some dirty reflection.

皓月长歌 2024-10-04 11:24:04
foreach ( var o in list ) {
    Console.WriteLine( o.ContactID );
}

仅当列表为 IEnumerable 时,这才有效,如下所示:

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

但您不能返回匿名类型,因为您必须定义返回类型(您不能返回 var) 和匿名类型不能有名称。如果你想传递它,你应该创建非匿名类型。实际上,除了查询内部之外,匿名类型不应该使用太多。

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

this will work only if list is IEnumerable<anonymous type>, like this:

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

but you can't return anonymous types, because you must define return type (you can't return var) and anonymous types can't have names. you should create non-anonymous type if you with to pass it. Actually anonymous types should not be used too much, except for inside of queries.

初相遇 2024-10-04 11:24:04

如果您有这样的方法:

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

您实际上不应该这样做,但是有一个 非常丑陋且不面向未来 您可以使用的技术:

  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 中的动态变量是解决这个问题的最佳方法。

If you have a method like this:

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

You shouldn't really do this, but there's a very ugly and not future-proof technique that you can use:

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

It relies on the fact (which can change!) that the compiler reuses anonymous types for types that have the same "shape" (properties names and types). Since your "example" matches the "shape" of the type in the method, the same type is reused.

Dynamic variables in C# 4 are the best way to solve this though.

氛圍 2024-10-04 11:24:04

您无法使用匿名类型执行此操作。只需创建一个 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 );
}

编辑:错过了问题的重要部分。现在已修复。
编辑:再次更改答案。见上文。

You cannot do this with anonymous types. Just create a Contact class/struct and use that.

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

Then you can do this:

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

...or this:

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

Of course you should in that case just do create a Contact list instead of an object list:

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

EDIT: Missed essential part of the question. Now fixed.
EDIT: Changed answer yet again. See above.

雪若未夕 2024-10-04 11:24:04

对于每个构造,用 var 替换 object 可能有效

replacing object with var in for each construct may work

乱世争霸 2024-10-04 11:24:04

我知道我参加聚会迟到了,但我研究了其他东西,发现了这个 文章回答了您的问题。

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

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

I know I'm late to the party but I researching somthing else and found this article which answers your question.

It is possible to cast the list of objects back into the anonymous type.

    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;
    }
裂开嘴轻声笑有多痛 2024-10-04 11:24:04

返回列表

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

list back

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;
}
掐死时间 2024-10-04 11:24:04

我会使用

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

,那么你根本不需要声明。
我相信更少的声明、更少的分号会导致更少的错误

i would use

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

then you dont need to declare at all.
i believe that less declaration, less semi-colon leads to less bug

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文