2008-11-04 15 views
1

У меня есть следующий код:вывод выражений при наследовании

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

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

Я знаю, что если я весь класс Base родовое, как это:

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

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

+0

Я добавил альтернативу, которая позволяет избежать требования «внутреннего» (и метода расширения) – 2008-11-04 13:19:41

ответ

6

Как насчет метода расширения, который вызывает фактическую реализацию (protected internal)? Единственным недостатком является то, что вы должны добавить 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); 
} 
+0

Хм, это решает другую проблему, связанную с некоторой проблемой наследования в форме алмаза, но также предоставляет метод FigureItOut для посторонних, мы 'придется подумать, если это компромисс, с которым мы можем жить. – 2008-11-04 12:54:15

+0

@lassevk - ну, внутренние аутсайдеры ... обратите внимание, что вы тоже можете сделать BaseExt внутренним ... – 2008-11-04 13:01:42

0

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