Доступ к свойству объекта DisplayClass во время выполнения

Среда: VS2017, C # 7.0 для .NET Core 2.1.

Я пытаюсь написать поддельный / макетный класс для использования в модульном тестировании, и у меня возникают трудности с доступом к свойству объекта DisplayClass, который, как я понимаю, имеет вид закрывающий класс анонимной функции.

Мой код выглядит так:

namespace MyCompany.Application.Web.Test.Fakes
{
    public class FakeElasticClient : IElasticClient
    {
        public FakeElasticClient() { }

        public Task<ISearchResponse<T>> SearchAsync<T>(Func<SearchDescriptor<T>, ISearchRequest> selector = null, CancellationToken cancellationToken = default(CancellationToken)) where T : class
        {
            var methodName = selector.Method.Name;
            dynamic tgt = selector.Target;
            object id = tgt?.GetType().GetProperty("id")?.GetValue(tgt, null);
            int? total;
            if (methodName.Contains("Quux"))
            {
                total = CountSomething((Guid)id);
            }
            else
            {
                total = CountSomethingElse((Guid)id);
            }

            return Task.Run(() => new FakeSearchResponse<T>(total ?? 0) as ISearchResponse<T>);
        }

        // … below here follows a couple thousand other methods

Приведение id в Guid вызывает NullReferenceException, хотя отладчик Visual Studio показывает, что объект tgt имеет свойство id:

Отладчик Visual Studio

Комментарии:

  • Я украл строку object id = … из этого ответа.
  • tgt.GetType() возвращает MyCompany.Application.Domain.Repository.Implementations.BusinessEntityRepository.<>c__DisplayClass8_0
  • tgt.GetType().GetProperties() возвращает пустой массив PropertyInfo.
  • Вдохновленный этим сообщением в блоге, я добавил [assembly: InternalsVisibleTo("MyCompany.Application.Web.Test")] атрибут как для MyCompany.Application.Domain.Repository.Implementations.BusinessEntityRepository, так и для MyCompany.Application.Web.Controllers классов, которые, насколько я могу судить, являются единственными двумя классами, участвующими в цепочке вызовов. Никакой разницы.
  • Я пробовал поиграть с IgnoresAccessChecksTo как описано здесь, но ничего не скомпилировать.

Как мне получить значение для id?


person kthy    schedule 13.03.2019    source источник
comment
Компилятор генерирует типы замыкания с полями, а не свойствами, поэтому id будет полем; попробуйте tgt.GetType().GetFields(). Тем не менее, я думаю, что вы слишком далеко заходите в модульном тестировании, если вам приходится иметь дело с деталями реализации компилятора.   -  person madreflection    schedule 13.03.2019
comment
На самом деле это довольно простой модульный тест, проблема в том, что значение, к которому мне нужно получить доступ, находится внутри анонимной функции, переданной методу. В любом случае вы совершенно правы, и это работает, когда я меняю строку на object id = tgt?.GetType().GetField("id")?.GetValue(tgt);. Если вы добавите это в качестве ответа, я отмечу, что это правильно. ????   -  person kthy    schedule 13.03.2019


Ответы (1)


Компилятор генерирует типы замыкания с полями, а не свойствами, поэтому id - это поле. Вместо этого используйте tgt.GetType().GetFields().

person madreflection    schedule 13.03.2019
comment
TIL разница между полями и свойствами. Спасибо! - person kthy; 13.03.2019