Question

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).

Was it helpful?

Solution

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);
}

OTHER TIPS

Unless it takes a parameter, it cant be inferred. Unless it assigns a return value, it cant be inferred.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top