I'm probably missing something very basic but I cannot figure out why I get a compilation error with a certain code and I don't get it in an almost identical code.
So I do get an error here:
//parent.GetChildren() returns a IEnumerable<IBase>
F1<T>(T parent, Func<string, T, string> func) where T: IBase
{
F1(parent.GetChildren(), func);
//This would wok instead:
//F1(parent.GetChildren().Select(c=> (T)c), func);
}
F1<T>(IEnumerable<T> children, Func<string, T, string> func) where T: IBase
{
...
}
but I don't here:
//parent.GetChildren() returns a IEnumerable<IBase>
F1<T>(T parent, Func<string, string, string> func) where T: IBase
{
//Works, no casting required
F1(parent.GetChildren(), func);
}
F1<T>(IEnumerable<T> children, Func<string, string, string> func) where T: IBase
{
...
}
Basically if I use the generic Type T in the passed parameter function as one of its parameters I get the following compilation errors:
Error 1: The best overloaded method match for 'ConsoleApplication1.Program.FooConsumer.Consume1<ConsoleApplication1.Program.IBase>(System.Collections.Generic.IEnumerable<ConsoleApplication1.Program.IBase>, string, System.Func<string,ConsoleApplication1.Program.IBase,string>)
' has some invalid arguments
Error 2: Argument '3': cannot convert from 'System.Func<string,T,string>
' to 'System.Func<string,ConsoleApplication1.Program.IBase,string>
'
Here is the full example code, please refer to commented code (uncomment to get compilation error):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
interface IBase
{
string GetName();
IEnumerable<IBase> GetChildren();
}
class Foo : IBase
{
private string _Name;
public Foo(string name)
{
_Name = name;
}
public string GetName()
{
return _Name;
}
public IEnumerable<IBase> GetChildren()
{
var r = new List<IBase>();
r.Add(new Foo("foo 1"));
r.Add(new Foo("foo 2"));
return r;
}
}
class FooConsumer
{
public string Consume1<T>(IEnumerable<T> objects, string template, Func<string, T, string> func) where T : IBase
{
var s = "";
foreach (var o in objects)
{
s += func(template, o);
}
return s;
}
public string Consume2<T>(IEnumerable<T> objects, string template, Func<string, string, string> func) where T : IBase
{
var s = "";
foreach (var o in objects)
{
s += func(template, o.GetName()) + "\n";
}
return s;
}
//Here if I don't cast each child as a T I get an error
public string Consume1<T>(T parent_object, string template, Func<string, T, string> func) where T : IBase
{
// return this.Consume1(parent_object.GetChildren(), template, func); //<-- UNCOMMENTING THIS WOULD NOT COMPILE
return this.Consume1(parent_object.GetChildren().Select(c => (T)c), template, func);
}
//Here I would expect it to behave identically, but instead I don't get an Error and code compiles fine.
//How can the last parameter be affecting the first parameter?!
public string Consume2<T>(T parent_object, string template, Func<string, string, string> func) where T : IBase
{
return this.Consume2(parent_object.GetChildren(), template, func); //<-- THIS CALL DOES NOT DO THE CAST BUT COMPILES JUST FINE!!!
}
}
static void Main(string[] args)
{
FooConsumer fc = new FooConsumer();
Foo f = new Foo("parent");
Func<string, IBase, string> func1 = (template, node) =>
string.Format(template, node.GetName());
Func<string, string, string> func2 = (template, name) =>
string.Format(template, name);
string s1 = fc.Consume1(f, "<li>{0}</li>", func1);
string s2 = fc.Consume2(f, "<li>{0}</li>", func2);
Console.WriteLine("Executing first:");
Console.WriteLine(s1);
Console.WriteLine("Executing second:");
Console.WriteLine(s2);
}
}
}
Many Thanks,
Giuseppe