2015-03-27 6 views
1

Я искал какой-то код на работе и наткнулся на то, с чем я не знаком.Зачем назначать лямбда-выражение частному полю?

здесь полную собственность им знакомы:

private int myVar; 
public int MyProperty 
{ 
    get { return myVar; } 
    set { myVar = value; } 
} 

, но потом я увидел (и я не могу вспомнить точно) это:

private int myVar = x => x.Something; 

Это было установлено в приложении, использующем CSLA.

+0

Требуется добавить, что типы полей и свойств не были int, как в примере выше, они были настраиваемыми типами. – Liger86

+6

Действительно ли код действительно компилируется? вы назначаете анонимную функцию переменной типа int? Это кажется невозможным. –

+0

Вышеприведенный код служит только для иллюстрации того, что я видел лямбда, назначенное для поля, и что это чуждо мне. – Liger86

ответ

1

Biscuits пишет о селекторах свойств (или полей) ... Для этого есть два вида использования: один (тот, о котором он говорил), чтобы получить имя поля/свойства.

Как это сделать?

Дано:

Expression<Func<Foo, int>> expression = x => x.Something; 

Вы делаете:

string name = ((MemberExpression)expression.Body).Member.Name; 

, как пишут другие, в C# 6.0 это будет почти бесполезным благодаря nameof() (что в целом быстрее, потому что это делается во время компиляции а во время выполнения), а в C# 5.0 частично бесполезно благодаря [CallerMemberName].

Второе использование заключается в том, что путем передачи Expression<>, который является «получателем» (функция, которая дала объект, возвращает значение чего-либо), метод может «построить» «сеттер».

Func<Foo, int> getter = expression.Compile(); 

var parameter = Expression.Parameter(expression.ReturnType); 

Action<Foo, int> setter = Expression.Lambda<Action<Foo, int>>(
    Expression.Assign(expression.Body, parameter), 
    new[] { expression.Parameters[0], parameter }).Compile(); 

Foo foo = new Foo(); 
setter(foo, 5); // Example of use of the setter 
int value = getter(foo); // Example of use of the getter 

Если вы должны использовать один временный сеттер, это довольно медленнее, чем непосредственно отражение (потому что Expression s должен быть построен, а затем компилируются и так далее, а также в строительстве и компиляции (но а не при использовании) Expression есть отражение). Но если вам нужно использовать много раз геттер/сеттер, то он становится быстрее (если вы их «кешируете»), потому что использование построенного таким образом геттера/сеттера почти так же быстро, как прямой доступ к свойству/поле (медленная часть заключается в создании геттера/сеттера)

0

Использование выражения лямбда как переменной (открытого или закрытого) подобно использованию функции, которая может быть изменена.

, например, я мог бы сделать что-то вроде этого

var myFavoriteFunction = (x) => x.FirstFunction(); 

//do some work 
myFavoriteFunction(someobject) 

//now change the function 
myFavoriteFunction = (x) => x.SecondFunction(); 

myFavoriteFunction(someobject) 

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

+1

Первая строка неверно, поскольку компилятор не может знать тип 'x' и конечный тип делегата. Напишите это как: 'Func myFav = x => x.FirstFunction()' – xanatos

+0

@xanatos прав - но это не потому, что C# не может вывести тип, а потому, что он может быть либо 'Func <...>', либо 'Выражение >' - это одна цена, которую мы должны заплатить, чтобы LINQ работал задушить;) – Carsten

+0

@ CarstenKönig Вы частично правы ... Это можно увидеть с чем-то вроде var var myvar =() => 5'. Ошибка такая же. Но на том, что вы написали, я добавлю, что компилятор даже не может знать, какой именно тип делегата использовать. В .NET нет эквивалентности делегатов с одинаковой подписью. Поэтому 'Func ' «отличается», что «Predicate ', в то время как обе имеют одну и ту же подпись до типа возврата. – xanatos

1

Использование выражений таким образом также называется списком свойств.

Правильный синтаксис для этого на самом деле так.

private Expression<Func<Foo, int>> myVar = x => x.Something;

Есть бесчисленное множество применений для них, и один типичный пример, чтобы избежать необходимости в «прописывать» имена членов, которые должны иначе быть напечатаны в виде строковых литералов (которые остаются непроверенный компилятором и оказывается затруднительным к рефактору).

В этом примере представлено одно практическое приложение.

Implementing INotifyPropertyChanged - does a better way exist?

Вы также видите это широко используется в Fluent interface реализации, такие как Fluent NHibernate.

В случае появления выражения nameof(), входящего в C# 6, однако мы скоро увидим, что эта техника исчезает.

http://davefancher.com/2014/12/02/c-6-0-nameof-expressions/

+1

Если вы хотите откройте имя что-то, вы напишете его как «Выражение > myVar' – xanatos

+0

Спасибо xanatos. Ты прав! Я исправил соответственно. – Biscuits

+3

@ Печенье: Еще до введения оператора 'nameof' в C# 6 существует пользовательский атрибут' [CallerMemberName] '(введенный с C# 5), который позволяет более эффективную альтернативу выражениям' Expression > ' метод получения имени свойства. – stakx

0

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

Func<int,int> doubleMyNumber = (i) => 2 * i; 

Это работает как делегат, написанный как анонимная функция. Более подробная информация здесь: https://msdn.microsoft.com/fr-fr/library/bb397687.aspx

В C# 6 вы сможете увидеть еще более странные обозначения, как этот

public int AgeInDogYears() => Age * 7; 

Вы будете в состоянии написать тело метода как лямбда-выражения. http://csharp.2000things.com/2014/11/03/1217-using-lambda-expressions-for-function-members/