刚问:
为什么'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。
规格告诉
有点可疑。由于您的方法将dynamic作为参数,因此它符合“动态绑定”
的条件
有这样的规范有什么意义?或者在什么情况下DateTimeOffset.Parse不会返回STRUCT(暂时忘记DLR ......)?
如果类中的所有方法/重载都具有相同的返回类型,那么编译器需要很聪明,以便长期获得性能优势。
答案 0 :(得分:4)
当您使用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结构,但对于仅在运行时才能知道的编译器......
答案 1 :(得分:1)
这是一个很好的例子,说明你对返回类型的假设开始出错了。
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
{1}}。
所以,如果你要这样做......
dynamic value = "Hello, world!";
Bar bar = new Baz();
var returnValue = bar.Foo(value);
... returnValue
在运行时的值为1234
,而不是"Hello, world!"
。
现在,在现实世界中,这是疯狂邪恶。虽然可以完全重新绑定预期会以某种方式执行某些操作的功能,但做这样荒谬的事情只会让人们感到困惑。话虽如此,它在CLR中是完全可能的。
TL; DR:当您使用dynamic
时,您无法始终确定您认为正确的事情。