Can anyone explain why the following code won't compile
public static class Utilities
{
public delegate void Unary<T>( T t );
public delegate void Binary<First, Second>( First first, Second second );
public delegate void Tertiary<F, S, T>( F first, S second, T third);
public static Unary<Second>
BindFirst<First, Second>( Binary<First, Second> function, First first )
{
return delegate( Second second ) {
function( first, second );
};
}
public static Binary<S, T>
BindFirst<F, S, T>( Tertiary<F, S, T> function, F first )
{
return delegate( S second, T third) {
function( first, second, third);
};
}
public static void Foreach<T>( ICollection<T> collection, Unary<T> function )
{
foreach ( T t in collection )
{
function( t );
}
}
}
public class Sample
{
private Dictionary<string, string> m_strings;
private void Add( string value, string key )
{
m_strings[key] = value;
}
public Sample( ICollection<string> strings )
{
string value = "some string value";
// Error here, can't determine template parameters for BindFirst
Utilities.Foreach( strings,
Utilities.BindFirst( Add, value ) );
}
}
The compiler error is:
The type arguments for method 'Utilities.BindFirst<First,Second>(Utilities.Binary<First,Second>, First)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Now obviously, I can call the BindFirst method and specify the type arguments explicitely, but this becomes super ugly when the parameters are lengthy names, or when I'm trying to bind a Tirtiary delegate.
It seems like the compiler should be able to determine that Add fits the delegate Binary<string, string> from it's declaration, which pins the First and Second template types. Can anyone explain why it can't determine these arguments implicitely
Thanks in advance,
Luke

Generics: trouble inferring type parameters from usage.
PaulBSteelerFan
In both your Foreach function and Add function you are missing a return type, changing both declarations to:
public static void Foreach<T>( ICollection<T> collection, Unary<T> function )
and
private void Add( string value, string key )
should resolve your problem, however you will likely need to change the types to something other than void for your purposes.
LN42
With the voids added, the compiler still can't seem to deduce that the Add funtion matches the Binary<string, string> delegate that it should be looking for.
Thanks for noticing the error.
Luke
rdx
I think it's because 'Add', when passed as an argument to the BindFirst method, is treated as a 'method group', which is very much a different kind of thing from a delegate. And according to section 25.6.4 of the ECMA spec for C# (the "Inference of type arguments" section), "Nothing is inferred from the argument ... if any of the following are true: ... The argument is a method group".
So that's the short answer: nothing can be inferred from a method group argument.
But that's not a terribly useful answer - it's just a cryptic way of saying "Because the spec says so." More useful would be to attempt to say why the spec says so.
This seems to fall into a class of problems caused by the slight hackiness of the way in which method names can be used where a delegate is expected. It's a nice feature in that it lets you write more succinct code. But it was a bit of a bolt-on feature - C# 1.1 didn't have it. The way it was worked in seems to mean that it's not as simple as saying "You can put a method name anywhere you would otherwise have required a delegate."
I think this is the core issue: the only reason you can put a method group where a delegate used to be required is that there's an implicit conversion from method groups to delegates. The problem you're seeing is caused by the fact that it's an implicit conversion. If a method group were essentially equivalent to a delegate, then it would work as you expect.
Bearing that in mind, let's consider what you're asking of the compiler here. You're calling the BindFirst method, which expects a delegate as its first parameter, but you've given it something else: a method group. That's OK in the same way that it's OK to pass an int to a method that expects a double - the C# compiler can generate an implicit conversion for you. However, you're asking it to 'see through' the implicit conversion and perform type inference based on the source of that implicit conversion.
If the compiler was happy to infer generic type arguments from any viable implicit conversion from the parameter type, then I guess you could end up with some pretty peculiar inferences in some obscure scenarios, and they decided to keep it simple.
I guess they could have introduced a special inference rule for method groups. Arguably it would have been nice. In this case it would clearly have made sense. But once you start taking overloaded methods, and co/contravariance into account, it might well be that it's hard to pin down a set of rules for acceptable inferences without introducing a great deal more complexity.
Mufaddal
My block was the fact that the Bind function's first parameter is of type MulticastDelegate, and loses the type information that would allow imlpicit inferrence of the "T" type parameter ("S" is bound by the second argument to Bind).
It would be nice if a MethodGroup->Delegate cast could somehow preserve the type information if the MethodGroup has type parameters. Something like dynamically generating a CustomDelegate<S, T> : MulticastDelegate or something... I imagine that there are all sorts of complexities and unintended consequences for that sort of thing though.
Anyway, what I've ended up doing is something like:
public static Binary<string, string> Add
{
get { return doAdd; }
}
public static void doAdd(string s, string t)
{
}
where explicitely specifying type parameters at the call-site gets unwieldy. It's obvious at the property defenition what is going on, and my call site is clean and fits inside of 80-ish columns.
Thanks for the help.