2010-07-21 3 views
2

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

public class C{} 
public static class E { 
    public static void Foo(this C o) { } 
} 
class D:C { 
    void test() { 
// Foo(); // will not compile 
    this.Foo(); // compile ok 
    } 
} 

естественно в классе реального сценария C будет классом я не имею доступа к его исходному коду

Кто-нибудь знает, почему это странное требование использовать это ключевое слово?

+6

Я предполагаю, что вы намеревались «D» наследовать от 'C'. В вашем примере кода это не так. –

+4

и что foo() и this.foo() должны быть Foo() и this.Foo(); –

+2

Ни один из ваших фрагментов не будет компилироваться, поэтому либо исправить фрагменты, либо исправить комментарии. –

ответ

8

Глядя на C# спецификации, раздел 7.6.5.2 указывает, что метод расширения вызовы применяются только для вызовов метода следующих форматов:

expr . identifier () 
expr . identifier (args) 
expr . identifier <typeargs> () 
expr . identifier <typeargs> (args) 

Когда это автономный вызов метода, существует нет expr, поэтому он не ищет метод расширения. Это следует из того, что без expr он не знает, каким должен быть первый аргумент метода расширения.

+0

+1 для ссылки на спецификацию, хотя я не согласен с тем, что он не знает, каким должен быть первый аргумент. Он всегда будет «этим», так как любой вызов неквалифицированной функции для метода экземпляра на 100% идентичен, если вызывается как «this.Foo()», поэтому нет причин, чтобы он не мог вывести «this.». В соответствии с возражениями «волшебных слов» Эрика Липперта это кажется просто надзором (или попыткой ограничить возможную путаницу), поскольку компилятор * может * знать со 100% уверенностью, каков должен быть первый аргумент. –

+2

Я подозреваю, что из-за того же синтаксиса можно вызвать статические методы в содержащем классе - для одного есть «это», а для другого - нет, но оба выглядят одинаково. Наличие предшествующего 'expr' ограничивает его методами экземпляра. – thecoop

+0

Я согласен с adam - спасибо –

2

Это не потому, что D является подклассом C. (что в вашем примере, кстати, это не так.) Это потому, что методы расширения - это «синтаксический сахар», который заставляет казаться, что метод принадлежит классу, даже если это не так. Эта функция компилятора превращает любой вызов callingObject.Foo(); в Foo(callingObject); компилятором.

В вашем прокомментированном коде компилятор не знает, что использовать в качестве первого параметра для вашего метода расширения (т. Е. Он не знает, чего вы хотите this C o), поскольку ни один объект типа C или подкласс из C это называется.

Если вы хотите вызвать метод расширения из базового класса, вы увидите то же поведение.

Надеюсь, что это поможет устранить некоторые путаницы.

+0

После того, как я исправил свой код, что я имею в виду - у меня есть чувство, что вы правы в ответ - но я могу утверждать, что компилятор ДОЛЖЕН знать что я хочу использовать это - так как это действительно экземпляр C –

+0

@Lee Мне хотелось бы, чтобы компилятор завтракал утром, хе-хе. Но, серьезно, я согласен, что это то, что компилятор, вероятно, может быть изменен для распознавания. IMO, вы не должны создавать методы расширения, если у вас есть доступ к изменению исходного кода. –

2

Если у вас есть доступ к изменению кода класса ... Почему вы хотите использовать метод расширения? Методы расширения полезны для тех классов, которые у вас нет возможности изменять. Я бы понял, что это будет насуговаться практикой программирования.

+0

+1 Использование методов расширения на классах, которые вы пишете, является плохим. – dthorpe

+0

как я писал в исходном вопросе - я привел здесь пример с полным исходным кодом, но в реальном сценарии у меня нет доступа к коду C –

+0

Если у вас нет кода для кода, почему вы беспокоитесь о как он компилируется? –

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