2015-09-01 2 views
0

Рассмотрим следующий код:Почему общие методы расширения вызываются с родительским типом от родителя?

public static class ParentHelper { 
    public static string GetTypeString<T>(this T parent) where T : Parent { 
     return typeof(T).ToString(); 
    } 
} 

public abstract class Parent { 
    public string GetMyType(bool withReflection) { 
     return withReflection 
     ? typeof(ParentHelper) 
      .GetMethod("GetTypeString") 
      .MakeGenericMethod(GetType()).Invoke(null, new object[] { this }) as string 
     : this.GetTypeString(); 
    } 
} 

public class Child : Parent { 
} 

void Main() { 
    Child child = new Child(); 
    child.GetMyType(false).Dump();   // Parent 
    ((Parent) child).GetMyType(false).Dump(); // Parent 
    child.GetMyType(true).Dump();    // Child 
    ((Parent) child).GetMyType(true).Dump(); // Child 
} 

К моему удивлению, метод GetMyType возвращает разные значения в зависимости от того, как он вызывает GetTypeString (см комментарии в Main метод).

Есть ли способ для метода GetTypeString расширения для работы с ребенком типа класса вместо родителем одного, при использовании нормального object.ExtensionMethod() синтаксиса?

Обратите внимание, что этот код является минимальным примером, который я мог бы собрать вместе - мое использование совсем другое (не возвращать тип, а скорее атрибут, украшающий дочерний класс).

+0

Если вы хотите, чтобы тип времени исполнения 'parent' использовал' parent.GetType() 'вместо' typeof (T) '. – PetSerAl

+0

Я был * просто * понял это, но это делает все сложнее, потому что я хочу использовать 'T' в следующем общем вызове' return CallAnotherMethod '. – ErikE

ответ

3

Да, вместо этого необходимо заменить typeof(T) на parent.GetType().

Они делают разные вещи.

2

this.GetTypeString(); составлен в ParentHelper.GetTypeString<Parent>(), потому что это тип, переданный от Parent.GetMyType.

Обычное решение - сделать Parent родовое своего ребенка (он же любопытно рекурсивный шаблон), как:

public abstract class Parent<TChild> where TChild : Parent<TChild> 
{ 
    public string GetMyType() 
    { 
     return ((TChild)this).GetTypeString(); 
    } 
} 

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

Смежные вопросы