The actual call in Main
gets translated into a CallSite
, because you're invoking the call with a dynamic param
. The CallSite
does all the preparation it needs in order to invoke this method at run-time. But, the problem is, that Assert
has a Conditional
attribute on it, which means it needs to pass information to the compiler pre-processor at compile-time
This blog post explains:
Conditional attributes can be placed on methods (and attributes in
whidbey) to instruct the compiler to conditionally remove calls to the
function if a symbol is not defined. This can be useful for debug-only
functionality, like Debug.Assert, which has a Conditional("DEBUG") on
it.
Conditional takes a string argument. If that string is defined (as
determined by the compiler's preprocessor), then the compiler emits
the method call. If the symbol is not defined, C# still compiles the
method, but does not compile the calls.
And later, to strengthen our point:
The Conditional attribute is entirely handled by the compiler without
any cooperation from the runtime. The method is still jitted normally,
but the compiler just doesn't emit the calls if the symbol is not
defined.
Now, we have a conflict. We can't pass parameters to the compiler pre-processor at run-time (to tell it if "DEBUG" is defined or not), only at compile-time, but the method will only be invoked at run-time, because that's when we'll infer the type of our dynamic
value.
That's why the binder yells at run-time that this method can't actually be invoked, because that would be breaking the ConditionalAttribute
.
Bonus:
This is what actually gets called:
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));