C# “我可以吗?”;“动态”;类型在泛型集合中安全地变化<;动态>;?

C# “我可以吗?”;“动态”;类型在泛型集合中安全地变化<;动态>;?,c#,.net,dynamic,c#-4.0,C#,.net,Dynamic,C# 4.0,根据我对的回答,我想检查一下我对即将推出的C#4的动态类型的理解 在本例中,我们有一个集合,它表示从未知数据库表中提取的记录中的字段。较旧的代码(pre-.Net 4)需要这样一个集合来保存类型为Object的项。撇开这样一个集合的优点不谈,我想知道当您将对象更改为动态时会发生什么 一方面,我希望,由于动态类型的问题都是在运行时解决的,所以只要程序员没有对集合中某个特定项的预期类型犯任何打字错误或错误,一切都应该很好 另一方面,我想知道上一句中的“all”这个词。运行时是否会缓存第一次访问动态属

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

在本例中,我们有一个集合,它表示从未知数据库表中提取的记录中的字段。较旧的代码(pre-.Net 4)需要这样一个集合来保存类型为
Object
的项。撇开这样一个集合的优点不谈,我想知道当您将
对象
更改为
动态
时会发生什么

一方面,我希望,由于动态类型的问题都是在运行时解决的,所以只要程序员没有对集合中某个特定项的预期类型犯任何打字错误或错误,一切都应该很好


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

好的,而不是等待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);
    }
}
class-Foo
{
公共字符串foo=“foo!”;
}
分类栏
{
公共int bar=42;
}
班级计划
{
静态void Main(字符串[]参数)
{
var test=新列表();
test.Add(newfoo());
测试。添加(新条());
Console.WriteLine(test[0].foo.Substring(0,3));
Console.WriteLine(测试[1].bar.ToString(“000”);
Console.ReadKey(true);
}
}

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

您可以将dynamic看作是使用反射和MethodInfo编写所有方法调用的语法糖。Invoke()-在引擎盖下,它不完全是这样工作的,但是你可以这样想,因为所有的“通过dynamic=>perf每秒调用1000个方法”考虑因素都伴随着它。

就字典/列表而言,它只能看到
对象<代码>动态
主要在旁观者的眼中-即调用代码;引擎盖下是“物体加一点糖”。所以你不应该在这里看到任何问题

证明:

    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);
    }
static void Main()
{
Console.WriteLine(IsObject());//false
Console.WriteLine(IsObject());//true
Console.WriteLine(IsObject());//true
Console.WriteLine(IsObject());//false
}
静态布尔等值对象()
{
返回typeof(T)=typeof(object);
}

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

DLR检查缓存以查看 给定的操作已绑定 针对当前的一组参数。 所以在我们的例子中,我们要做一个类型 基于1、2和运行时进行匹配 d型。如果我们找到了缓存, 然后返回缓存的结果。如果 我们没有缓存命中,那么 DLR检查接收器是否正常工作 田园诗般的主题。这些家伙 本质上是知道如何 注意自己的约束,例如 作为COM IDispatch对象,真实动态 对象,如Ruby或Python对象, 或者实现的某个.NET对象 IDynamiObject接口。如果是 所有这些,然后DLR取消 给IDO并要求它绑定 行动

请注意,调用 IDO to bind是一个表达式树 表示绑定的结果。 如果不是IDO,则DLR 调用语言活页夹(在我们的 案例中,要绑定的C#运行时绑定器) 手术。C#运行时绑定器 将绑定该操作,并将返回 表示 绑定的结果。第2步或第3步 发生了什么,结果呢 表达式树被合并到 缓存机制,使任何 后续调用可以针对 缓存而不是反弹

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


显然,前者的性能要高得多;确定何时可以仅基于类型进行缓存是一件棘手的事情。详细解释所有这些逻辑是如何运作的需要相当长的时间;希望有一天我、克里斯或山姆能在博客上发表文章。

“它不是那样工作的”是言过其实了。如果你用的是C#binder,它一点也不起作用。@Eric说得很对,你说得很对,但为了概念化“动态”的工作原理,更容易给出“忽略风阻力”的解释,这正是我所担心的。在我的简单示例中,运行时很容易知道它们是不同的类型。但是缓存确实会发生,所以如果您要做很多这样的事情,可能会遇到边缘情况。真的,虽然,我不认为这会是一个问题的情况下,提示这个问题,这是很好的知道。@乔尔:当然,可能有错误的缓存未命中的政策。如果你发现了,请告诉我!:)