[英]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.