为什么我不能使用Debug.Assert()接受动态和返回bool的方法?

时间:2015-02-17 13:39:28

标签: c# .net dynamic conditional-attribute

这是我的代码:

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',因为它具有条件属性

是的,Assert()上有ConditionalAttribute。然而,无论方法接受什么,只有一个whatever()方法返回bool

运行时到底抱怨什么?为什么不能使用bool并将其传递给Assert()

1 个答案:

答案 0 :(得分:1)

Main中的实际通话被转换为CallSite,因为您正在使用dynamic param来调用该通话。 CallSite执行所需的所有准备工作,以便在运行时调用此方法。但是,问题是Assert上有Conditional属性,这意味着它需要在编译时

blog post explains

  

条件属性可以放在方法(和属性)中   whidbey)指示编译器有条件地删除对。的调用   如果未定义符号,则起作用。这对于仅调试非常有用   功能,如Debug.Assert,它有一个条件(“DEBUG”)   它

     

条件采用字符串参数。 如果定义了该字符串(如   由编译器的预处理器确定),然后编译器发出   方法调用。如果没有定义符号,C#仍会编译   方法,但不编译调用。

后来,加强我们的观点:

  

条件属性完全由编译器处理而没有   来自运行时的任何合作。该方法仍然正常进行,   但是如果符号不是,编译器就不会发出调用   定义

现在,我们发生了冲突。我们不能在运行时将参数传递给编译器预处理器(告诉它是否定义了“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));