откуда взято 'p' в NotifyPropertyChanged(p => QuantitySaved);
Лямбда передается методу NotifyPropertyChanged
.Существует одна перегрузка этого метода.Имеет формальный тип параметра Expression<Func<ViewModelBase, T>>
.То есть формальный параметр ожидает получить лямбду, которая принимает ViewModelBase и возвращает T для некоторого T.
p
- это параметр, который принимает лямбда.
Компилятор может сделать вывод, что автор кода не учел явно указывать тип параметра lambda.Автор мог бы также написать:
NotifyPropertyChanged((ViewModelBase p) => QuantitySaved);
, если бы они хотели быть откровенными об этом.
как компилятор узнает, что нужно заполнить типзначение ViewModelBase с нуля?
Компилятор проверяет все возможные перегрузки NotifyPropertyChanged
, которые могли бы принять лямбду в этой позиции аргумента.Он выводит формальный тип параметра лямбда из типов делегата , которые находятся в типах формальных параметров методов NotifyPropertyChanged
.Пример может помочь.Предположим, у нас есть:
void M(Func<int, double> f) {}
void M(Func<string, int> f) {}
и вызов
M(x=>x.Length);
Компилятор должен определить тип лямбда-параметра x.Каковы возможности?Существует две перегрузки M. Оба принимают делегата в формальном параметре M, соответствующем первому аргументу, переданному в вызове.В первом случае функция имеет тип от int до double, поэтому x может иметь тип int.Во втором формальный параметр M - это функция от строки до int, поэтому x может быть строкой.
Теперь компилятор должен определить, какой из них правильный.Для того, чтобы первый из них был правильным, тело лямбды должно возвращать двойное число.Но если x - это int, на x нет свойства Length, которое возвращает double.Так что x не может быть int.Может ли x быть строкой?Да.Существует свойство Length для x, которое возвращает int, если x является строкой.
Поэтому компилятор определяет, что x является строкой.
Эти выводы могут усложнить экстраординарно .Несколько более сложный пример:
void M<A, B, C>(A a1, Func<List<A>, B> a2, Func<B, C> a3) {}
...
M(123, x=>x.Count.ToString(), y=>y.Length);
Вывод типа должен выводить типы A, B, C и, следовательно, типы x и y.Компилятор сначала делает вывод, что A должно быть int, поскольку a1 равно 123. Затем он делает вывод, что x должно быть List<int>
из этого факта.Затем он делает вывод, что B должен быть строкой, и, следовательно, y является строкой, и, следовательно, C является типом y.Length
, который является int.
Все становится намного сложнее, поверь мне.
Если вас интересует эта тема, я написал несколько статей и снял несколько видеороликов на тему различных типов вывода типов, выполняемых компилятором.См.
http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/
для всех деталей.
Для забавы я изменил код с 'p' на 'this', так как SampleViewModel наследует от ViewModelBase, но меня встретил ряд ошибок компилятора, первая из которых указала на недопустимое выражение «=>». Это немного смутило меня, так как я думал, что это сработает.сторона лямбда-оператора - это список лямбда-параметров;«this» никогда не является допустимым списком лямбда-параметров.Компилятор ожидает, что за «this» последует «.SomeMethod ()» или что-то подобное;компилятор предполагает, что за «this» никогда не последует «=>».Когда вы нарушаете это предположение, случаются плохие вещи.