首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >异构列表是否有特定的用途?

异构列表是否有特定的用途?
EN

Software Engineering用户
提问于 2012-02-01 13:59:31
回答 5查看 6.5K关注 0票数 14

来自于C#和Java背景,我习惯于我的列表是同构的,这对我来说是有意义的。当我开始使用Lisp时,我注意到列表可以是异构的。当我开始在dynamic中乱搞C#关键字时,我注意到,在C# 4.0中,也可以有异构列表:

List<dynamic> heterogeneousList

我的问题是什么是重点?在进行处理时,异构列表的开销似乎要大得多,而且如果需要在一个地方存储不同的类型,则可能需要不同的数据结构。我的天真是在丑恶的脸上培养出来的,还是真的有必要有一个不同的列表呢?

EN

回答 5

Software Engineering用户

回答已采纳

发布于 2012-02-01 16:18:09

Oleg、拉尔夫·L、基恩·舒普克的论文“强类型异源集合”不仅包含了Haskell中异构列表的实现,而且还包含了一个关于何时、为什么以及如何使用HLists的令人鼓舞的例子。特别是,他们正在使用它进行类型安全编译时检查数据库访问。(想想LINQ,事实上,他们所引用的论文是Erik Meijer等人的Haskell论文,它导致了LINQ。)

引用HLists文件导言段的话:

以下是需要异构集合的典型示例的开放列表:

  • 应该存储不同类型条目的符号表是异构的。它是一个有限映射,其中结果类型取决于参数值。
  • XML元素是异构类型的。事实上,XML元素是受正则表达式和1-歧义属性约束的嵌套集合。
  • SQL查询返回的每一行都是从列名到单元格的异构映射。查询的结果是异构行的同构流。
  • 将高级对象系统添加到函数式语言需要一种将可扩展记录与子类型和枚举接口相结合的异构集合。

请注意,在您的问题中给出的例子实际上并不是异类列表,因为这个词是常用的。它们是弱类型或非类型化列表。事实上,它们实际上是同质列表,因为所有元素都是相同类型的:objectdynamic。然后,您将被迫执行强制转换或未检查的instanceof测试或类似的操作,以便能够真正有意义地使用元素,这使得它们的类型比较弱。

票数 18
EN

Software Engineering用户

发布于 2012-02-01 14:39:45

长话短说,异构容器以运行时性能换取灵活性。如果你想要一个“材料列表”而不考虑特定类型的东西,那么异质性就是最好的选择。list是动态输入的,而且大多数东西都是一个缺点--无论如何都是盒装值的列表,因此,对性能的影响是很小的。在Lisp世界中,程序员的生产力被认为比运行时性能更重要。

在动态类型化语言中,与异构容器相比,同构容器实际上具有较小的开销,因为添加的所有元素都需要进行类型检查。

关于选择更好的数据结构,您的直觉是正确的。一般来说,您可以在代码上设置的契约越多,您就越了解它是如何工作的,并且它变得更可靠、更易于维护。但是,有时您确实需要一个异构容器,如果需要的话,应该允许您拥有它。

票数 5
EN

Software Engineering用户

发布于 2012-02-01 14:52:38

在函数式语言(如lisp)中,使用模式匹配来确定列表中的特定元素发生了什么。在C#中等效的是一个if...elseif语句链,它检查元素的类型并在此基础上执行操作。不用说,函数模式匹配比运行时类型检查更有效。

使用多态性将更接近模式匹配。也就是说,让列表中的对象匹配一个特定的接口,并在该接口上为每个对象调用一个函数。另一种选择是提供一系列以特定对象类型作为参数的重载方法。以对象作为其参数的默认方法。

代码语言:javascript
运行
复制
public class ListVisitor
{
  public void DoSomething(IEnumerable<dynamic> list)
  {
    foreach(dynamic obj in list)
    {
       DoSomething(obj);
    }
  }

  public void DoSomething(SomeClass obj)
  {
    //do something with SomeClass
  }

  public void DoSomething(AnotherClass obj)
  {
    //do something with AnotherClass
  }

  public void DoSomething(Object obj)
  {
    //do something with everything els
  }
}

这种方法提供了对Lisp模式匹配的近似。访问者模式(在这里实现的,是使用异构列表的一个很好的例子)。另一个例子是消息调度,在这种情况下,在优先级队列中有特定消息的侦听器,并使用责任链,调度程序传递消息,第一个与消息匹配的处理程序处理消息。

另一方面是通知为消息注册的每个人(例如,事件聚合器模式通常用于ViewModels模式中的松散耦合)。我使用以下构造

代码语言:javascript
运行
复制
IDictionary<Type, List<Object>>

添加到字典的唯一方法是一个函数。

代码语言:javascript
运行
复制
Register<T>(Action<T> handler)

(对象实际上是传入处理程序的WeakReference )。所以在这里我必须使用List,因为在编译时,我不知道封闭类型是什么。然而,在运行时,我可以强制它是字典的关键。当我想启动我所呼吁的事件时

代码语言:javascript
运行
复制
Send<T>(T message)

我再一次解决这个问题。使用List没有任何好处,因为我无论如何都需要转换它。因此,正如你所看到的,这两种方法都有其优点。如果要使用方法重载动态地分派一个对象,动态就是这样做的。如果你被迫抛砖引玉,不妨使用Object。

票数 2
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/132835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档