Почему я не могу использовать Debug.Assert() с методом, принимающим динамический и возвращающий bool?

Вот мой код:

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() имеет ConditionalAttribute в теме. Все же есть точно один whatever() метод, который возвращает bool независимо от того, что метод принимает.

На что конкретно жалуются во время выполнения? Почему он не может использовать bool и передать его в Assert()?

1 ответ

Фактический звонок в Main переводится в CallSite потому что вы вызываете вызов с dynamic param, CallSite выполняет всю подготовительную работу, необходимую для вызова этого метода во время выполнения. Но проблема в том, что Assert имеет Conditional атрибут, который означает, что он должен передавать информацию препроцессору компилятора во время компиляции

Этот пост в блоге объясняет:

Условные атрибуты могут быть помещены в методы (и атрибуты в whidbey), чтобы дать указание компилятору условно удалить вызовы функции, если символ не определен. Это может быть полезно для функциональности только для отладки, такой как Debug.Assert, в которой есть условие ("DEBUG").

Условно принимает строковый аргумент. Если эта строка определена (как определено препроцессором компилятора), то компилятор отправляет вызов метода. Если символ не определен, 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));
Другие вопросы по тегам