Async flavors of `Util.CacheAsync` and `Util.Cache` can throw `RuntimeBinderException`
This issue seems to be very similar to this one from last year.
I've run into a case where Util.Cache
and Util.CacheAsync
will throw RuntimeBinderException
s if the query is modified at all between runs, with the message "'object' does not contain a definition for 'Task'".
The issue seems to crop up when I'm attempting to cache a generic dictionary that has a non-built in type as the value type.
Reproduction:
async Task Main() { var val = await Util.CacheAsync(async () => await GetDictFoo(), "cache_key", out bool cacheHit); // issue does occur if using the method to allow 'faulted task' caches, too //var val = Util.Cache(async () => await GetDictFoo(), "cache_key", out bool cacheHit); // issue does not seem to occur with built in types //var val = await Util.CacheAsync(async () => await GetDictString(), "cache_key", out bool cacheHit); (cacheHit ? "hit" : "miss").Dump(); // add any characters to this comment and re-run: } [Serializable] class Foo { } async Task<Dictionary<string, Foo>> GetDictFoo() => new(); async Task<Dictionary<string, string>> GetDictString() => new();
The first run will print "miss", and each subsequent run will print "hit". Until the query is modified, when the exception will be thrown. (Any change that gets it to recompile is enough, just adding or removing a character in a comment will get it done.
If you comment out the first and uncomment the second example there, and Kill Process and Execute, the same behavior is reproducible with the Util.Cache
method as it was with Util.CacheAsync
.
Switching to the last example, the behavior does not occur when the type being returned only has built-in types. It will continue to print "hit" as expected.
I can't see the link between what causes the Dictionary<string, string>
to be happy, while Dictionary<string, Foo>
doesn't want to play ball.
Thanks as always Joe! Hope you're well.
Comments
This occurs because I've not written a cache converter for dictionaries - it's on the TODO list.