这是我的代码:
class Program
{
static void Main(string[] args)
{
dynamic param = null;
System.Diagnostics.Debug.Assert(whatever(param));
}
static bool whatever(object param)
{
return true;
}
}
当我运行它时,我会得到带有以下消息的RuntimeBinderException
:
无法动态调用方法"Assert",因为它具有Conditional属性
是的,Assert()
上有ConditionalAttribute
。然而,无论方法接受什么,只有一个whatever()
方法会返回bool
。
运行时到底抱怨什么?为什么它不能使用bool
并将其传递到Assert()
?
Main
中的实际调用被转换为CallSite
,因为您使用dynamic param
调用该调用。CallSite
完成了在运行时调用此方法所需的所有准备工作。但是,问题是,Assert
上有一个Conditional
属性,这意味着它需要在编译时将信息传递给编译器预处理器
这篇博客文章解释道:
条件属性可以放置在方法上(和中的属性whidbey)来指示编译器有条件地移除对函数,如果未定义符号。这只对调试有用功能,如Debug.Assert,它在
Conditional接受字符串参数如果该字符串被定义为由编译器的预处理器确定),则编译器发出方法调用。如果没有定义符号,C#仍然编译方法,但不编译调用
后来,为了加强我们的观点:
Conditional属性完全由编译器处理运行时的任何合作该方法仍然正常运行,但是如果符号不是定义
现在,我们发生了冲突。我们不能在运行时将参数传递给编译器预处理器(告诉它是否定义了"DEBUG"),只能在编译时传递,但该方法只能在运行时调用,因为那时我们将推断dynamic
值的类型。
这就是为什么绑定器在运行时大喊这个方法实际上不能被调用,因为这会破坏ConditionalAttribute
。
奖金:
这就是所谓的
private static void Main(string[] args)
{
object param = null;
if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Assert", null, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
Action<CallSite, Type, object> arg_CB_0 = Program.<Main>o__SiteContainer0.<>p__Site1.Target;
CallSite arg_CB_1 = Program.<Main>o__SiteContainer0.<>p__Site1;
Type arg_CB_2 = typeof(Debug);
if (Program.<Main>o__SiteContainer0.<>p__Site2 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site2 = CallSite<Func<CallSite, Type, object, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.None, "whatever", null, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
arg_CB_0(arg_CB_1, arg_CB_2, Program.<Main>o__SiteContainer0.<>p__Site2.Target(Program.<Main>o__SiteContainer0.<>p__Site2, typeof(Program), param));