【问题标题】:Can the "dynamic" type vary safely in a generic collection<dynamic>?“动态”类型可以在泛型集合<dynamic> 中安全地变化吗?
【发布时间】:2011-01-11 14:15:06
【问题描述】:

根据我对 this question 的回答,我想检查一下我对 C# 4 即将推出的 dynamic 类型的理解。

在这种情况下,我们有一个集合,它表示从未知数据库表中提取的记录中的字段。较旧的代码(.Net 4 之前的版本)需要这样的集合来保存 Object 类型的项目。除了这样一个集合的优点,我想知道当你将Object 更改为dynamic 时会发生什么。

一方面,我希望由于动态类型的事情都是在运行时解决的,所以只要程序员没有对特定项目的预期类型产生任何错别字或错误,一切都应该没问题集合。

另一方面,我想知道上一句中的“全部”一词。运行时是否会缓存第一次访问动态属性时的结果,导致后续使用不同类型的调用失败?

【问题讨论】:

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


    【解决方案1】:

    这是 Sam 博客中的相关内容,简要介绍了缓存策略。

    http://blogs.msdn.com/samng/archive/2008/10/29/dynamic-in-c.aspx

    DLR 检查缓存以查看 给定的动作已经被绑定 反对当前的一组论据。 所以在我们的例子中,我们会做一个类型 基于 1、2 和运行时的匹配 d.类型如果我们有缓存命中, 然后我们返回缓存的结果。如果 我们没有缓存命中,那么 DLR 检查接收器是否 一个 IDynamicObject。这些人是 本质上是知道如何 照顾他们自己的约束力,比如 作为 COM IDispatch 对象,真实动态 对象,例如 Ruby 或 Python 对象, 或一些实现的 .NET 对象 IDynamicObject 接口。如果是 任何这些,然后 DLR 取消 到 IDO 并要求它绑定 行动。

    注意调用的结果 要绑定的 IDO 是一个表达式树 表示绑定的结果。 如果不是 IDO,则 DLR 调用语言绑定器(在我们的 情况下,C# 运行时绑定器)绑定 操作。 C# 运行时绑定器 将绑定动作,并返回 表示的表达式树 绑定的结果。执行第 2 步或第 3 步 发生了,结果 表达式树被合并到 缓存机制,以便任何 随后的调用可以针对 缓存而不是被反弹。

    但是,Sam 没有提到的正是缓存未命中策略是什么。有两种主要的缓存未命中策略:(1)当参数类型更改时触发缓存未命中,(2)当参数标识更改时触发缓存未命中。

    显然前者的性能要好得多;确定我们何时可以仅根据类型进行缓存是很棘手的。对所有这些逻辑如何运作的详细解释需要相当长的时间。希望我或 Chris 或 Sam 会在这些日子里写一篇关于它的博客文章。

    【讨论】:

    • 这正是我所担心的。在我的简单示例中,运行时很容易知道它们是不同的类型。但是缓存确实会发生,因此如果您要执行很多这些操作,可能只是可能会遇到边缘情况。不过,真的,我认为对于提示这个问题的案例来说这不会是一个问题,这很高兴知道。
    • @Joel:当然,缓存未命中策略中可能存在错误。如果你找到了,请告诉我! :)
    【解决方案2】:

    您可以将动态视为使用 Reflection 和 MethodInfo.Invoke() 编写所有方法调用的语法糖——在底层它的工作方式并不完全一样,但您可以认为它是以这种方式工作的,伴随着所有“通过动态调用 1000 个方法/秒 => 被谋杀的性能”的考虑。

    【讨论】:

    • “它不完全像那样工作”是夸大其词。如果您使用的是 C# binder,它根本就没有任何效果
    • @Eric 很公平,你说的很对,但为了概念化“动态”的工作原理,更容易给出“无视风阻”的解释
    【解决方案3】:

    dictionary/list而言,只能看到objectdynamic 主要是在旁观者的眼中 - 即 调用 代码;在引擎盖下是“对象加一点糖”。所以你不应该在这里看到任何问题。

    证明:

        static void Main()
        {
            Console.WriteLine(IsObject<int>()); // false
            Console.WriteLine(IsObject<object>()); // true
            Console.WriteLine(IsObject<dynamic>()); // true
            Console.WriteLine(IsObject<string>()); // false
        }
        static bool IsObject<T>()
        {
            return typeof(T) == typeof(object);
        }
    

    【讨论】:

      【解决方案4】:

      好的,与其等待答案,我启动了 Visual Studio 2010 beta 2,这个测试程序运行良好:

      class Foo
      {
          public string foo = "Foo!";
      }
      class Bar
      {
          public int bar = 42;
      }
      
      class Program
      {
          static void Main(string[] args)
          {
              var test = new List<dynamic>();
              test.Add(new Foo());
              test.Add(new Bar());
      
              Console.WriteLine(test[0].foo.Substring(0,3));
              Console.WriteLine(test[1].bar.ToString("000"));
      
              Console.ReadKey(true);
          }
      }
      

      我想确保我不仅检查了具有不同名称的属性,而且它们也具有不同的类型,并且我在每种类型中使用了彼此不兼容的特性。这似乎表明如果有任何东西被缓存,运行时足够聪明,知道何时使用缓存,何时不使用。我仍然想听听是否有人知道这可能不成立的边缘情况,或者关于为什么会成立的更权威的评论。

      【讨论】:

        猜你喜欢
        • 2021-03-17
        • 1970-01-01
        • 1970-01-01
        • 2011-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多