【问题标题】:cast list of anonymous type to list of object将匿名类型列表强制转换为对象列表
【发布时间】:2017-12-19 13:01:20
【问题描述】:

我正在尝试创建一个匿名列表,该列表可以包含任何具有 intellisense 支持但不创建 classdata type

所以我找到了以下使用匿名类型的解决方案。

  var list = new[]
  { 
     new { Number = 10, Name = "Smith" },
     new { Number = 10, Name = "John" } 
  }.ToList();

  foreach (var item in list)
  {
    Console.WriteLine(item.Name);
  }

但是如果我想要一个返回匿名类型以上的方法怎么办。

public List<object> GetData()
{

    var list = new[]
    {
        new { Number = 10, Name = "Smith" },
        new { Number = 10, Name = "John" }
    }.ToList();

    return list;

}

编译时错误:

不能隐式转换类型 'System.Collections.Generic.List' 到 'System.Collections.Generic.List

是否可以将匿名类型列表转换为支持智能感知的对象列表?

更新:

我们不想创建类型的原因,因为我们只想使用匿名类型进行一些数据操作并填充一些其他对象。

【问题讨论】:

  • 我怀疑只是创建一个类型将是这里解决方案的最短/最干净的路径。为什么要努力避免这种情况?
  • 匿名类型并不意味着在通用或本地上下文之外使用,所以不是。您必须返回 objectdynamic 或元组类型之一或类似类型,但不能使用智能感知返回匿名类型。为此,我们已经有了正确的解决方案,创建一个适当的命名类型。
  • 新 C# 编译器中的元组支持命名,但这是一个技巧,它很快就会崩溃。同样,正确的方法是使用正确的命名类型。
  • 然后返回 dynamic 并希望一切顺利。它不会给你智能感知,但它会让你很容易地接触到里面的成员。
  • 如果您可以使用 c# 7 功能 - 您可以使用命名元组。

标签: c# anonymous-types


【解决方案1】:

以下是可能的方法:

  1. 返回一个List&lt;object&gt;,表示接收端没有智能感知
  2. 返回List&lt;dynamic&gt;,这意味着您在接收端没有智能感知,但可能比通过反射更容易访问您知道的成员
  3. 返回一个List&lt;T&gt;,但您必须提供一个示例说明T 的外观,这在运行时不会比dynamic 更安全
  4. 返回 C# 7 附带的新类型的元组

只需确保列表属于该类型,即可轻松解决第 1 点和第 2 点:

...
}.ToList<object>();

第 3 点是一个 hack,但我会在下面发布。

第 4 点可以用这个语法解决:

public List<(int Number, string Name)> GetData()
{

    var list = new[]
    {
        (Number: 10, Name: "Smith"),
        (Number: 10, Name: "John")
    }.ToList();

    return list;
}

这会给你一段时间的智能感知,但属性的命名是编译器的一个hack,如果你开始传递这些值,它们很容易回退到.Item1.Item2


要将对象转换为特定类型,您可以使用仅在创建匿名对象的同一程序集中有效的 hack,即在您的代码中使用的多个匿名类型,它们具有相同的属性,以相同的顺序,具有相同的属性类型,最终都是相同的匿名类型。

因此,您可以使用以下 hackish 代码将 object 强制转换为特定的匿名类型:

public T AnonymousCast<T>(object value, T example) => (T)value;
public IEnumerable<T> AnonymousCastAll<T>(IEnumerable<object> collection, T example) => collection.OfType<T>();

你会像这样在你的情况下使用它:

var d = AnonymousCast(GetData()[0], new { Number = 0, Name = "" });

这并不比使用dynamic 更安全,因为不能保证从GetData 返回的对象实际上 是那种匿名类型。

简而言之,使用命名类型。

【讨论】:

  • 我可以通过 GetData() 而不是 GetData()[0] 吗?
  • 添加了AnonymousCastAll,但不要使用这些!您不妨只使用dynamic。我可以很容易地做到AnonymousCast(o, new { Foo = 42, Bar = 17 }),它会编译但不会运行。您将获得智能感知,而不是对象实际提供的内容。
  • 猜猜这个post 与您发布的信息相同。非常感谢您的努力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多