Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Получения данных CallStack


Автор: Lomir 11.6.2009, 19:46
Возможно ли в С# получить данные с котороми на стеке была вызвана функция?
т.е. в идеале хочу сделать что то вроде:
Код

void SomeFunction(object someObj1, object someObj2)
{
    ValidateNotNull();

}

void ValidateNotNull() 
{
    StackTrace trace = new StackTrace();
    foreach(var param = trace.GetFrame(1).GetMethod().GetParameters())
    {
        // так ты знаем только тип параметров, но не переданное значение
        // а возможно ли получить еще и значение someObj1, someObj2? Чтобы сделать что то похожее:
        if (значение == null)
            throw new Exception("{0} is null" param.Name);
    }
}

Или может можно решить проблему в проверкой на null входящих параметров как нибуть проще?

Автор: PashaPash 11.6.2009, 20:18
Lomir, очень простое решение - просто вручную проверять параметры на null. В разы читабельнее, и работает в случае "все должны быть не null, кроме одного".

Автор: Lomir 12.6.2009, 09:02
Цитата

Lomir, очень простое решение - просто вручную проверять параметры на null. В разы читабельнее, и работает в случае "все должны быть не null, кроме одного". 

ИМХО Это не решение. Весь достаточно тупой код должен ренерироваться автоматически во время исполнения с помощью шаблонов, рефлексии и т.д. Зачем в ручную проверять в КАЖДОЙ функции парамерты и плодить сотни ненужных строк тупого кода, если это можно автоматизировать (если конечно можно вытащить значение парамертов из стэка). Лично мне очень не нравиться когда открываешь функцию с 4 или больше парамертами и видеш екран, а то и полтора екрана, тупых проверок типо:
Код

if (param != null)
{
  throw new SomeException("param is null");
}

Гораздо читабельнее иметь один метор Validate(); который проверят состояние обьекта на пригодность работы + проверяет нужные входящие парамерты на not null. А потом сразу сама логика функции.




Автор: PashaPash 12.6.2009, 09:25
Цитата(Lomir @  12.6.2009,  09:02 Найти цитируемый пост)
ИМХО Это не решение. Весь достаточно тупой код должен ренерироваться автоматически во время исполнения с помощью шаблонов, рефлексии и т.д. Зачем в ручную проверять в КАЖДОЙ функции парамерты и плодить сотни ненужных строк тупого кода, если это можно автоматизировать (если конечно можно вытащить значение парамертов из стэка).

Затем что только сама функция (ее автор) знают как именно валидировать параметры. И набор правил в общем случае уникален для КАЖДОЙ функции. "Не рабтать если someObj1 == null" - это часть самой логики функции, а не общее ограничение вообще  всех функций в приложении.  "все параметры не null" - достаточно редкий случай, и, IMHO, не стоит потенциальных проблем с производительностью.

Если часто видишь по полтора экрана проверок - то у тебя в коде функции часто принимают по 10-15 параметров, и надо что-то в консерватории менять, а не вставлять uber-хаки.

По теме - сомневаюсь в самой возможности вытащить значения из стэка без отладчика - между { и вызовом Validate происходит довольно много действий (в debug) и значений someObj1, someObj2 с стэке может уже не быть.

Автор: Lomir 12.6.2009, 09:55
По 10-15 уж точно не передаються, а вот по 4-6 довольно часто. 6 обьеков это 24 строчки безсмысленного кода. В случае когда какие то парамерты могут быть null утчен, работает немного измененный выриант.
Код

void SomeFunction(object someObj1, object someObj2)
{
    ValidateNotNull(someObj1, someObj2);
}
void ValidateNotNull(param object[] parameters) 
{
    foreach(var param in parameters)
    {
       if (param == null)
       {
          // List upperParam = GetListOfProvidedParametersInUpperFuntion();
          // Map parameter via ref equality and get its name
          // Or maybe there is other way to get parameter param name?
          throw new Exception("{0} is null", paramName);
       }
    }
}

Если какой-то параметр может быть null, мы его просто не передаем в ValidateNotNull и он не проверяется. При этом этот вариант не будет иметь никаких проблем с производительность, так как тут используется рефлексия тока в случаенеправильного использования, и оно будет исправленно.

Это не uber-хак, а просто обощение стандартный действий програмиста. По такой логике можно сказать что generic'и и мета-програмирование это тоже  uber-хаки.

ИМХО проверка параметров не является частью логики функции, так как не является полезной работой функции (а в конечной версии програмы этот код вопше не используется). В особо критических ко времени приложениях обычно вопше ничего не проверяют, а просто пишут в документации и в случае неправильных параметров получают Undefined Behavior.

Как обьекты могут быть не на стеке? Они же могут (и даже будут) использоваться после успешного окончания функции ValidateNotNull().

Автор: archeg 12.6.2009, 16:48
Вообще для этого существуют всякие либы типа Spring.net или Enterprise Library. И не надо придумывать велосипеды)

Автор: PashaPash 12.6.2009, 21:04
Цитата(Lomir @  12.6.2009,  09:55 Найти цитируемый пост)
По 10-15 уж точно не передаються, а вот по 4-6 довольно часто. 6 обьеков это 24 строчки безсмысленного кода. В случае когда какие то парамерты могут быть null утчен, работает немного измененный выриант.

Цитата(Lomir @  12.6.2009,  09:55 Найти цитируемый пост)

Если какой-то параметр может быть null, мы его просто не передаем в ValidateNotNull и он не проверяется. При этом этот вариант не будет иметь никаких проблем с производительность, так как тут используется рефлексия тока в случаенеправильного использования, и оно будет исправленно.

Этот вариант лучше, но тоже хромает - т.к. упирается в ту же проблему - достать значения из чужого стэка, что проблематично без отладочных символов.
Может быть что-то этого, в качестве компромиса
Код

        void ValidateNotNull(Dictionary<string, object> parameters) 
        {
            foreach(var param in parameters)
            {
               if (param.Value == null)
               {
                   throw new ArgumentNullException(param.Key);
               }
            }
        }

        void SomeFunction(object someObj1, object someObj2)
        {
            ValidateNotNull(new Dictionary<string, object>()
            {
                { "someObj1", someObj1 },
                { "someObj2", someObj2 }
            });
        }


Цитата(Lomir @  12.6.2009,  09:55 Найти цитируемый пост)
Это не uber-хак, а просто обощение стандартный действий програмиста. По такой логике можно сказать что generic'и и мета-програмирование это тоже  uber-хаки.

generic'и не пытаются вывести тип из имени переменной. хотя было бы неплохо - var intStringDictionary = new(); вот когда научатся - тоже станут убер-хаками.
Цитата(Lomir @  12.6.2009,  09:55 Найти цитируемый пост)
ИМХО проверка параметров не является частью логики функции, так как не является полезной работой функции (а в конечной версии програмы этот код вопше не используется). В особо критических ко времени приложениях обычно вопше ничего не проверяют, а просто пишут в документации и в случае неправильных параметров получают Undefined Behavior.

Для критических ко времени приложений существуют Trace/Debug.Assert, которые можно вырезать из релиза.

Цитата(Lomir @  12.6.2009,  09:55 Найти цитируемый пост)
Как обьекты могут быть не на стеке? Они же могут (и даже будут) использоваться после успешного окончания функции ValidateNotNull(). 

Зато значения (теоретически) могут быть не те. Например, проц/jit могут переставить местами строки 4 и 5. Причем вылезет это только в release configuration.
Код

void SomeFunction(object someObj1, object someObj2)
{
    var someNewValue = new object();
    ValidateNotNull();
    someObj1 = someNewValue;
}


Добавлено через 12 минут и 1 секунду
archeg, да, интерсепторы вполне решают проблему, довольно красиво. Но велосипеды - интереснее ;)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)