Pregunta

Tengo el siguiente código:

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

Recibo este mensaje de error del compilador:

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.

Si cambio la llamada a FigureItOut a esto:

FigureItOut((Descendant c) => c.Name);

Entonces funciona. ¿Hay alguna forma de obtener el primer ejemplo para compilar cambiando la clase base en su lugar?

Sé que si hago que toda la clase Base sea genérica, así:

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

Entonces funciona, pero prefiero no hacer eso, cualquier otro truco que pueda emplearse, tal vez a nivel de método (es decir, cambiar FigureItOut de alguna manera).

¿Fue útil?

Solución

¿Qué tal un método de extensión que llama a la implementación real ( protegida interna )? El único inconveniente es que debe agregar this. .

Esto funciona porque el parámetro source (a través de this ) infiere un tipo para 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; }
}

Como alternativa (si el interno es un problema), considere hacerlo estático, con un argumento de instancia que se use principalmente para la inferencia de tipos:

protected static void FigureItOut<TClass, TMember>(TClass source, Expression<Func<TClass, TMember>> expr)
{

}

public void TestMethod()
{
    FigureItOut(this, c => c.Name);
}

Otros consejos

A menos que tome un parámetro, no se puede inferir. A menos que asigne un valor de retorno, no se puede inferir.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top