Вывод выражения при наследовании
-
06-07-2019 - |
Вопрос
У меня есть следующий код:
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);
}
Другие советы
Если он не принимает параметр, он не может быть выведен. Если оно не присваивает возвращаемое значение, оно не может быть выведено.