I am writing a simple Memoize
helper that allows caching method results instead of computing them every time. However, when I try to pass a method into Memoize
, the compiler can't determine the type arguments. Aren't they obvious from my method signature? Is there a way around this?
Sample code:
using System;
using System.Collections.Concurrent;
public static class Program
{
public static Func<T, V> Memoize<T, V>(Func<T, V> f)
{
var cache = new ConcurrentDictionary<T, V>();
return a => cache.GetOrAdd(a, f);
}
// This is the method I wish to memoize
public static int DoIt(string a) => a.Length;
static void Main()
{
// This line fails to compile (see later for error message)
var cached1 = Memoize(DoIt);
// This works, but is ugly (and doesn't scale to lots of type parameters)
var cached2 = Memoize<string, int>(DoIt);
}
}
Error message:
error CS0411: The type arguments for method 'Program.Memoize<T, V>(Func<T, V>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
Give an example. What are the types of function arguments in Python? Hence, we conclude that Python Function Arguments and its three types of arguments to functions. These are- default, keyword, and arbitrary arguments. Where default arguments help deal with the absence of values, keyword arguments let us use any order.
By default, a function must be called with the correct number of arguments. Meaning that if your function expects 2 arguments, you have to call the function with 2 arguments, not more, and not less.
An argument is the value that are sent to the function when it is called. By default, a function must be called with the correct number of arguments. Meaning that if your function expects 2 arguments, you have to call the function with 2 arguments, not more, and not less.
What makes me confused is that the generic And () method works without specifying the type arguments explicitly Basically, type inference for generic type parameters works based on the arguments you pass to the method. So And () works, because you're passing in an isAdult.
Isn't
DoIt()
signature compatible withFunc<string, int>
?
Yes it is. It's fine to convert it to that specific type, like this for example:
Func<string, int> func = DoIt;
var cachedDoit = Memoize(func);
The problem you're running into is that type inference basically doesn't work particularly well with method group conversions. When you pass DoIt
as an argument, that's a method group. In your case it only refers to a single method, but it could refer to multiple methods, with different signatures... and that complicates things.
I often see this come up with LINQ, where I'd like to call foo.Select(SomeMethodGroup)
, but type inference fails. There's some support for method groups within type inference, but it's not everything we might want it to be.
This isn't a matter of the C# team being lazy... type inference is hugely complicated, and any change is really fraught with danger in terms of backward compatibility. It's in section 7.5.2 of the C# 5 specification if you want to have a look - but frankly that's part of the spec where I get lost really quickly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With