2012-05-05 5 views
4

если честно (часть этого вопроса) here , но теперь у меня есть другой вопрос.Ковариация бьет бетонный тип?

public class Base 
{ 
    public void Foo(IEnumerable<string> strings) { } 
} 

public class Child : Base 
{ 
    public void Foo(IEnumerable<object> objects) { } 
} 


List<string> lst = new List<string>(); 
lst.Add("aaa"); 
Child c = new Child(); 
c.Foo(lst); 

(п C# 3 будет позвонить: Base.Foo в C# 4 будет позвонить: Child.Foo)

Im в FW4! , Позволяет говорить об этом

при всем уважении к ковариации: , когда я пишу c.Foo(lst); -

видит как подписи !!! (lst это IEnumerable СТРОКИ!) но STILL - он выбирает IEnumerable<object> ??

Ковариантность сильнее, чем конкретный тип?

+0

Вы можете заставить его выбрать один из методов, назначив подпись. 'c.Foo ((IEnumerable ) lst)' в вашей ситуации ни одна подпись не соответствует реальному конкретному типу, поэтому вы не должны делать никаких предположений. (Ответ ниже дает обоснование из спецификации для выбора, который, по-видимому, отличается от 3.0, но в этих серых областях я предпочитаю просто явно определять поведение с литой) –

+0

@jamietre, нет, это не работает. Ваш код все равно вызовет метод из 'Child'. – svick

+0

Ну, ты просто разрушил весь мой мир! Конечно. Похоже, что «набор методов кандидата» уменьшен до того, как будут устранены различия. –

ответ

5

Это не потому, что ковариация сильнее, а потому, что C# сначала выбирает метод «ближе». Итак, он выглядит на Child.Foo(), решает, что он применим (благодаря ковариации) и даже не смотрит на Base.Foo().

Предполагается, что конкретный тип «знает» больше, поэтому его методы следует рассматривать первыми.

См §7.6.5.1 из C# 4 спецификации:

Набор методов-кандидатов сокращается до содержат только методы из самых производных типов: для каждого метода CF в наборе, где С представляет собой тип, в котором объявлен метод F, все методы, объявленные в базовом типе C, удаляются из набора.

+0

и если я хочу базовый func? –

+0

Затем вам нужно использовать приведение: либо неявное, изменяя тип переменной на «Base», либо явно: '((Base) c) .Foo (lst)'. – svick

+0

Или вы можете использовать ключевое слово 'base', если вы делаете вызов в' Child': 'base.Foo (lst);' –

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