mercredi 13 mars 2019

Accessing property on DisplayClass object at runtime

Environment: VS2017, C# 7.0 targeting .NET Core 2.1.

I'm trying to write a fake/mock class to use for unit testing, and I'm having difficulties accessing a property on a DisplayClass object, which I understand is a closure class from an anonymous function.

My code looks like this:

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

Casting id to Guid throws a NullReferenceException, even though the Visual Studio debugger shows the tgt object has an id property:

Visual Studio debugger

Comments:

  • I have stolen the object id = … line from this answer.
  • tgt.GetType() returns MyCompany.Application.Domain.Repository.Implementations.BusinessEntityRepository.<>c__DisplayClass8_0
  • tgt.GetType().GetProperties() returns an empty PropertyInfo array.
  • Inspired by this blog post I added an [assembly: InternalsVisibleTo("MyCompany.Application.Web.Test")] attribute to both the MyCompany.Application.Domain.Repository.Implementations.BusinessEntityRepository and the MyCompany.Application.Web.Controllers class, which as far as I can tell are the only two classes involved in the call chain. Didn't make any difference.
  • I tried futzing around with IgnoresAccessChecksTo as described here, but couldn't make anything compile.

How do I retrieve the value for id?





Aucun commentaire:

Enregistrer un commentaire