Можно ли получить доступ к объекту вызывающего из трассировки стека и установить его свойство - PullRequest
0 голосов
/ 04 июля 2011

Привет У меня есть возможный недостаток дизайна, и мне нужно решить его с помощью метода расширения. Допустим, у меня есть класс, и у него есть свойство StringCollection. Пример кода

public class MyProblematicClass
{
    public IDbAccess Db{get;set;}
    public StringCollection Errors{get;set;}

    public MyProblematicClass(IDbAcces db){ Db=db;}

    public int SetItem(Item i)
    {

        var id = Db.Save(i);
        this.Errors = Db.Erros;
        return id;
    }

}

Что я делаю, так это то, что в своем классе модульных тестов я имитирую IDbAccess. Этот класс проверяет объект в соответствии с атрибутами. Если возникает какая-либо ошибка, она не попадает в базу данных, она просто заполняет собственную коллекцию ошибок. Для модульного теста я использую другой dbclass, который просто запускает процедуры проверки, и вот проблема, я не могу получить ошибку. Позвольте мне привести пример для дальнейшего понимания (я знаю, что дизайн проблематичен, но сейчас я хочу разобраться с ним, ничего не меняя)

public static class MyDbExtension
{
   public static Save(Item i)
   {
     Validation v = new Validation();
     var erros =    v.ValidateObject(i);
     //Here is problem i cannot pass it to MyProblematicClass
      if ( errors.Count > 0 )
         return -1;
     else 
        return 1;


    /* what I want to is :
     var stackTrace = new StackTrace(); get stack trace
     var object = stackTrace.GetFrame(1).GetMethod().GetObject() or sth like that. get object
     object.GetProperties()[0].SetValue(object,errors,null);  find property and set it.
   */
   }
}

в моем модульном тесте:

public class UnitTest
{
   Mock<IDbAccess> _db ;
   MyProblematicClass _mpc;
   pubic Setup()
   {

       _db.Setup(x=>x.Save(It.IsAny<Item>).Returns(u =>MyDbExtension.Save(u));
      _mpc = new MyProblematicClass(_db.Object);

   }

 public void SetItem_EmptyObject_Contains3Erros()
 {
    Item i = new Item();
    _mpc.SetItem(i);
    //At this point i cannot set _mpc.Errors
 }

Чего я хочу достичь, так это в моем классе DbExtension, могу ли я получить доступ к классу вызывающего и установить его свойство Errors? Я пытался, но это вряд ли было еще. Если у кого-нибудь найдется достойное решение, я буду признателен, и, конечно, вы сможете прокомментировать проблемы с дизайном.

Редактировать

Я ценю ответ Алекса, он только что сказал: игнорируй метод Save, просто смейся над свойством Erros, и все будет в порядке. Это имеет смысл, но я задаюсь вопросом: возможно ли получить доступ к Stack Trace и манипулировать свойством объекта метода методов вызова?

Заранее спасибо.

Ответы [ 4 ]

1 голос
/ 08 июля 2011

Не уверен, что полностью понял вопрос, но вы не можете получить доступ к параметрам в стеке из обычной программы.Метаданные времени выполнения касаются только статической информации (метод, свойства, константы и т. Д.).

Я считаю, что только отладчик (который рассматривается как отдельный зверь) может сделать это без изменения программы/ источник, и это имеет серьезную стоимость производительности.В качестве примечания, вот ссылка, которая объясняет, как создать свой собственный управляемый отладчик (.NET 4): CLR Managed Debugger (mdbg) Пример 4.0

Другое решение - это инструменткод (автоматически или с помощью инструмента), чтобы добавить некоторый вызов трассировки, который может захватить список параметров для каждого отслеживаемых методов.Такие инструменты, как PostSharp, могут сделать это.Вот еще одна ссылка: Неинвазивная трассировка и логирование

1 голос
/ 04 июля 2011

Вам необходимо установить возвращаемое значение _db.Errors, примерно так:

public class UnitTest
{   
     Mock<IDbAccess> _db ;   
     MyProblematicClass _mpc;   
     StringCollection errors;

     pubic Setup()   
     {       
          _db.Setup(x=>x.Save(It.IsAny<Item>).Returns(u =>MyDbExtension.Save(u));
          _db.Setup(x=>x.Errors).Returns(errors);      
          _mpc = new MyProblematicClass(_db.Object);   
     } 

     public void SetItem_EmptyObject_ContainsError() 
     {    
          errors.Add("Expected Error!");

          Item i = new Item();    
          _mpc.SetItem(i);    

          Assert.AreEqual("Expected Error!", _mpc.Errors[0]);
     }
 }

Должен признать, что я не очень слежу за вашим дизайном. Почему вы используете статический метод сохранения? Вы можете так же легко получить строку:

_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(-1);

Затем независимо протестируйте IDbAccess.Save ().

В вашем классе 'extension' метод save не имеет возвращаемого значения, а MyProblematicClass не проверяет возвращаемое значение перед назначением ошибок.

0 голосов
/ 13 июля 2011

Это не использует стек вызовов, но может принести вам некоторое расстояние:

class CalledClass
{
    public static void PokeCaller()
    {
        Program._this.Error = "Error!!!";
    }
}

class Program
{
    public string Error = null;
    [ThreadStatic] public static Program _this;
    public void Run()
    {
        _this = this;
        CalledClass.PokeCaller();
        Console.WriteLine(Error);
        Console.ReadKey();
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }
}

Создание ошибок [ThreadStatic] может быть более прямым способом сделать это ... или какой-то другой вариантна эту тему.Вы также можете объединить его с проверкой трассировки стека, чтобы узнать, действительно ли вы были вызваны чем-то с атрибутом «Ошибки» перед установкой ...

0 голосов
/ 12 июля 2011

Вы можете использовать API неуправляемой отладки для доступа к стеку вызовов и получения объекта, к которому была вызвана предыдущая функция в стеке.

Проблема в том, что в стеке может отсутствовать ожидаемый метод.В таких случаях, как встраивание и оптимизация хвостовых вызовов, стек вызовов не содержит предыдущий вызванный метод, что означает, что вы не можете надежно делать то, что хотите.

Для получения дополнительной информации см. этот ответ Эрика Липперта .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...