繁体   English   中英

C#DLR,使用动态关键字进行数据类型推断

[英]C# DLR, Datatype inference with Dynamic keyword

只是问问 :

为什么“ withOffset”变量在Parse方法返回Struct时被推断为动态变量?

dynamic str = "22/11/2013 10:31:45 +00:01";
var withOffset = DateTimeOffset.Parse(str);

在明确将其退回给Struct之后?

dynamic str = "22/11/2013 10:31:45 +00:01";
var withOffset = DateTimeOffset.Parse((string)str);

因为DateTimeOffset.Parse的返回类型是DateTimeOffset,所以编译器必须知道这一点。 请记住,无论在运行时调用什么方法,返回的值始终是DateTimeOffset。

规格说明

由于您的方法将动态作为参数,因此符合“动态绑定”的条件

有点腥。

有这样的规范有什么意义? 或在哪种情况下DateTimeOffset.Parse不会返回STRUCT(暂时忘记DLR。)?

如果类中的所有方法/重载都具有相同的返回类型,则编译器必须很聪明,以便长期获得性能收益。

使用dynamic ,整个表达式在编译时被视为动态表达式 ,这使编译器将所有内容都视为动态并获得运行时绑定。

在C#语言规范的7.2中对此进行了解释:

当不涉及动态表达式时,C#默认为静态绑定,这意味着在选择过程中会使用组成表达式的编译时类型。 但是,当上面列出的操作中的构成表达式之一是动态表达式时,该操作将动态绑定。

基本上,这意味着大多数操作(类型在规范的第7.2节中列出)中的任何元素都声明为dynamic则将其评估为dynamic ,结果将为dynamic


这是因为在str行下面是动态的

         dynamic str = "22/11/2013 10:31:45 +00:01";
        var withOffset = DateTimeOffset.Parse(str);

在编译时str是动态的,str的类型仅在运行时才知道,这就是编译器将withOffset视为动态的原因


它对您来说知道str被转换为datetime结构,但对于编译器来说,它仅在运行时才知道...

这是一个很好的例子,说明您对返回类型的假设开始出现问题。

public class Bar
{
    public string Foo(string value)
    {
        return value;
    }
}

如您所见, Bar显然具有一个实例方法Foo ,该方法接受一个字符串并返回一个字符串。

public class Baz : Bar, IDynamicMetaObjectProvider
{
    public DynamicMetaObject GetMetaObject(Expression parameter)
    {
        return new BazMetaObject(parameter, this);
    }
}

但是现在我创建了一个派生类,它也实现了IDynamicMetaObjectProvider 这是C#用于获取DynamicMetaObject的接口,该接口确定如何在运行时绑定动态调用。 例如:

public class BazMetaObject : DynamicMetaObject
{
    public BazMetaObject(Expression expression, Baz value)
        : base(expression, BindingRestrictions.Empty, value)
    {
    }

    public override DynamicMetaObject BindInvokeMember(
        InvokeMemberBinder binder, DynamicMetaObject[] args)
    {
        if (binder.Name == "Foo")
        {
            return new DynamicMetaObject(
                Expression.Convert(
                    Expression.Call(
                        typeof (BazMetaObject).GetMethod("DynamicFoo")
                    ),
                    typeof (object)
                ),
                BindingRestrictions.GetTypeRestriction(
                    this.Expression,
                    this.LimitType
                )
            );
        }

        return base.BindInvokeMember(binder, args);
    }

    public static int DynamicFoo()
    {
        return 1234;
    }
}

这种DynamicMetaObject重载将捕获对Foo所有调用,并将它们动态重定向到DynamicFoo ,后者具有完全不同的签名-包括返回int而不是string

所以,如果您要这样做...

dynamic value = "Hello, world!";

Bar bar = new Baz();
var returnValue = bar.Foo(value);

...运行时returnValue的值为1234 ,而不是"Hello, world!"

现在,在现实世界中,这是疯狂的邪恶。 尽管可以完全重新绑定期望以某种方式完成某项功能的功能,但这样做可笑的做法只会使人们感到困惑。 话虽如此,在CLR中完全有可能。

TL; DR:使用dynamic ,您始终无法确定自己认为正确的事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM