Domanda

Ho il seguente codice:

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

Ricevo questo messaggio di errore del compilatore:

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.

Se cambio la chiamata a FigureItOut a questo:

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

Quindi funziona. C'è un modo per ottenere il primo esempio da compilare modificando invece la classe base?

So che se rendo generica l'intera classe Base, in questo modo:

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

Quindi funziona, ma preferirei non farlo, qualsiasi altro hack che possa essere impiegato, forse a livello di metodo (ad es. cambiare FigureItOut in qualche modo).

È stato utile?

Soluzione

Che ne dici di un metodo di estensione che chiama l'implementazione effettiva ( protetto interno )? L'unico aspetto negativo è che devi aggiungere questo. .

Funziona perché il parametro source (tramite this ) fornisce un tipo per 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; }
}

In alternativa (se il interno è una seccatura), considera di renderlo statico, con un argomento di istanza usato principalmente per l'inferenza di tipo:

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

}

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

Altri suggerimenti

Se non accetta un parametro, non può essere dedotto. A meno che non assegni un valore di ritorno, non può essere dedotto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top