I have the following code:
using System;
using System.Linq;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
Descendant d = new Descendant();
d.TestMethod();
}
}
public class Base
{
protected void FigureItOut<TClass, TMember>(Expression<Func<TClass, TMember>> expr)
{
}
}
public class Descendant : Base
{
public void TestMethod()
{
FigureItOut(c => c.Name);
}
public String Name { get; set; }
}
I get this compiler error message:
The type arguments for method
'Base.FigureItOut<TClass,TMember>
(System.Linq.Expressions.Expression<System.Func<TClass,TMember>>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
If I change the call to FigureItOut to this:
FigureItOut((Descendant c) => c.Name);
Then it works. Is there a way to get the first example to compile by changing the base class instead?
I know that if I make the entire Base class generic, like this:
public class Base<TDescendant>
{
protected void FigureItOut<TMember>(Expression<Func<TDescendant, TMember>> expr)
{
}
}
public class Descendant : Base<Descendant>
{
public void TestMethod()
{
FigureItOut(c => c.Name);
}
public String Name { get; set; }
}
Then it works, but I'd rather not do that, any other hacks that can be employed, perhaps on the method level (ie. change FigureItOut somehow).
How about an extension method that calls the actual (protected internal
) implementation? The only downside is you have to add this.
.
This works because the source
parameter (via this
) infers a type for TClass
.
public class Base
{
protected internal void FigureItOut<TClass, TMember>(Expression<Func<TClass, TMember>> expr)
{
Debug.WriteLine("Got to actual method");
}
}
public static class BaseExt
{
public static void FigureItOut<TClass, TMember>(this TClass source, Expression<Func<TClass, TMember>> expr)
where TClass : Base
{ // call the actual method
Debug.WriteLine("Got to extension method");
source.FigureItOut(expr);
}
}
public class Descendant : Base
{
public void TestMethod()
{
this.FigureItOut(c => c.Name);
}
public String Name { get; set; }
}
As an alternative (if the internal
is a pain), consider making it static, with an instance argument that is used primarily for type inference:
protected static void FigureItOut<TClass, TMember>(TClass source, Expression<Func<TClass, TMember>> expr)
{
}
public void TestMethod()
{
FigureItOut(this, c => c.Name);
}