Can't Access Runtime Cache Using Reflection

2019-08-04 11:03发布

问题:

I am trying to get the expiry date of a HttpRuntime.Cache object, as per this answer:

https://stackoverflow.com/a/350374/1778169

The method is:

private DateTime GetCacheUtcExpiryDateTime(string cacheKey)
{
    object cacheEntry = Cache.GetType().GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(Cache, new object[] { cacheKey, 1 });
    PropertyInfo utcExpiresProperty = cacheEntry.GetType().GetProperty("UtcExpires", BindingFlags.NonPublic | BindingFlags.Instance);
    DateTime utcExpiresValue = (DateTime)utcExpiresProperty.GetValue(cacheEntry, null);    
    return utcExpiresValue;
}

When I try to use the above method, the first line won't compile:

An object reference is required for object.GetType()

If I replace Cache.GetType() with HttpRuntime.Cache.GetType() it compiles, but I get null returned from this part:

cacheType.GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).

What am I doing wrong?

I am using .NET 4.5. System.Web.Caching is version 4.0.0.0.

回答1:

You should have looked up the original source using the website Microsoft setup in order to find out more details of the HttpRuntime class, specifically the Cache property. If you look at line 2794 of the System.Web.HttpRuntime class you can see the following definition of the Cache property:

 public static Cache Cache {
        get {
              ...
        }
 }

Now since the property is static you cannot use the binding flags you are using, since right now you are looking for a NonPublic member that belongs to an Instance. In .NET static variables don't belong to an instance, therefor the code you posted will result in an exception being thrown; it simply cannot find the member you are looking for, since it not exists on the instance you provided -- it does however exists on the type definition of the class you are looking into (HttpRuntime).

In order to make your code work you will need to omit the binding flags, the internal .NET code that handles your request will now understand we are trying to lookup a static method: HttpRuntime.Cache.GetType().GetMethod("Get"). Note: if you want to have bindingflags (readability, understandabilty), you could add: BindingFlags.Public | BindingFlags.Static, which exactly does the same as whenever you omit the flags.

If you want to execute the method and get the result (get the actual Cache) you can invoke the MethodDefinition you just received from the GetMethod using Invoke(null, null).