samedi 16 juin 2018

Access private members of the generic instance within a generic class via reflection

I have looked at potentially duplicate questions, and this problem is not answered in any of them including Accessing Properties Through Generic Type Parameters

TLDR; typeof(T).GetProperty(propertyName) does not work within a generic class when propertyName of T is not declared public. Is there a workaround for this?

I have implemented an extension method that produces an IOrderedQueryable from a supplied string that contains the desired columns for sorting in an Entity Framework environment. The goal was to allow Order By clauses to be written in string form such as "+Age,+State,-Name" and produce the necessary expression to sort Entity Framework results by Age, State, and Name (descending), instead of having to write:

.OrderBy(m=>m.Age).ThenBy(m=>m.State).ThenByDescending(m=>m.Name).

The problem comes in when I try to access a class property that is marked internal. I cannot seem to find any way to force reflection to find that internal property.

In this particular case I have a datetime field in the database which is stored UTC but I want the end user to work with it in local time, so the value startTime, an internally scoped property is bound to the database and StartTime serves as a public accessor and provides access to the startTime value performing the necessary mapping to local time. I have a class defined as follows:

public class TimeInterval { 
   //other properties...
   internal startTime { get; set; } // bound to database, stores time in UTC
   public StartTime { 
      get { /*convert startTime to local time*/; } 
      set { /*convert value back to UTC and store in startTime*/;  }
   }
}

With EF I can write .OrderBy( m=>m.startTime ) and it works as expected; of course I cannot use .OrderBy( m=>m.StartTime ) because it is derived.

Within my extension function whose signature is

static public IOrderedQueryable<T> ParseOrderBy<T>( 
   this IQueryable<T> query, 
   string orderBy 
   )

which I would call using :

var query = query.ParseOrderBy<TimeInterval>( "startTime" );

my call to obtain the property reference to build a lamba expression returns null.

var property = typeof( T ).GetProperty( "startTime" );

property comes back null for anything that is not explicitly public.

The extension method is in the same namespace and assembly as the classes I expect it to operate.





Aucun commentaire:

Enregistrer un commentaire