Вопрос

У меня есть следующий код:

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

Я получаю это сообщение об ошибке компилятора:

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.

Если я изменю вызов FigureItOut на этот:

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

Тогда это работает. Есть ли способ получить первый пример для компиляции, изменив вместо этого базовый класс?

Я знаю, что если я сделаю весь базовый класс универсальным, вот так:

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

Тогда это работает, но я бы предпочел не делать этого, любые другие хаки, которые могут быть использованы, возможно, на уровне метода (т.е. как-то изменить FigureItOut).

Это было полезно?

Решение

Как насчет метода расширения, который вызывает фактическую ( внутренняя защита ) реализацию? Единственным недостатком является то, что вы должны добавить this. .

Это работает, потому что параметр source (через this ) выводит тип для 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; }
}
<Ч>

В качестве альтернативы (если internal является проблемой), рассмотрите возможность сделать его статичным с аргументом экземпляра, который используется главным образом для вывода типа:

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

}

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

Другие советы

Если он не принимает параметр, он не может быть выведен. Если оно не присваивает возвращаемое значение, оно не может быть выведено.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top