В основном, в первом примере вы привязываете i внутри обработчика onclick непосредственно к i вне обработчика onclick. Поэтому, когда i вне обработчика onclick изменяется, i внутри обработчика onclick тоже изменяется.
Во втором примере вместо привязки к num в onclick, вы передаете его в функцию, которая затем привязывает его к num в обработчике onclick. Когда вы передаете его в функцию, значение i копируется, не привязывается к num. Поэтому, когда i изменяется, num остается неизменным. Копия происходит потому, что функции в JavaScript являются «замыканиями», что означает, что как только что-то передается в функцию, оно «закрыто» для внешней модификации.
Изменить: nameof
прибыл в c # 6. Yay!
Нет nameof
/ infoof
и т. д .; это много обсуждается, но это то, что оно есть.
Существует способ сделать это с использованием лямбда-выражений в .NET 3.5 (и разбора дерева выражений), но на самом деле это не стоит накладные расходы. На данный момент я просто придерживаюсь строк (и модульных тестов, если вы решили не разорвать его).
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
class Program : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
static void Main() {
var p = new Program();
p.PropertyChanged += (s, a) => Console.WriteLine(a.PropertyName);
p.Name = "abc";
}
protected void OnPropertyChanged<T>(Expression<Func<Program, T>> property) {
MemberExpression me = property.Body as MemberExpression;
if (me == null || me.Expression != property.Parameters[0]
|| me.Member.MemberType != MemberTypes.Property) {
throw new InvalidOperationException(
"Now tell me about the property");
}
var handler = PropertyChanged;
if (handler != null) handler(this,
new PropertyChangedEventArgs(me.Member.Name));
}
string name;
public string Name {
get{return name;}
set {
name = value;
OnPropertyChanged(p=>p.Name);
}
}
}
Вы должны проверить это сообщение в блоге . Это дает вам возможность сделать это:
string propertyName = TypeHelper.GetPropertyName<User>(u => u.LastProjectCode);
PropertyInfo property1 = TypeHelper.GetProperty((SomeClass o) => o.InstanceProperty.Length);
PropertyInfo property2 = TypeHelper.GetProperty(() => SomeClass.StaticProperty.Length);
Переименование в Visual Studio / Resharper / Refactor Pro должно работать для вас тогда.
Свойство PropertyChangedEventArgs принимает только один конструктор, для которого требуется имя свойства как строка. Таким образом, по сути, использование INotifyPropertyChanged не означает, что на каком-то уровне, будь то высокая или низкая в вашей архитектуре, вам придется работать со строкой и ручным переименованием.
Самое простое решение - посмотреть на трассировку стека и полностью удалить каждую явную ссылку на свойство.
public String Name
{
get { return this.name; }
set
{
if (value != this.name)
{
this.RaisePropertyChanging();
this.name = value;
this.RaisePropertyChanged();
}
}
}
private String name = null;
private void RaisePropertyChanged()
{
String propertyName =
new StackTrace().GetFrame(1).GetMethod().Name.SubString(4);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(new PropertyChangedEventArgs(propertyName));
}
}
Код выводит имя свойства через трассировку стека из метода календаря - это метод установки свойств с именем set_<PropertyName>
. Если компилятор больше не следует этому соглашению об именах, код прерывается.
Другим решением является получение имени свойства из лямбда-выражения.
public static String GetPropertyNameFromLambdaExpression<TObject, TProperty>(
Expression<Func<TObject, TProperty>> expression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
Например
GetPropertyNameFromLambdaExpression<String, Int32>(s => s.Length)
вернет «Length
», как ожидалось. Производственная версия кода действительно требует дополнительных проверок и лучшей интеграции в остальную часть кода. Например, можно использовать вывод типа для общих аргументов.
UPDATE
И есть третье решение - вы можете использовать MethodBase.GetCurrentMethod()
внутри свойства getter или setter для получения имя метода setter или getter.
public String Name
{
get { return this.name; }
set
{
if (value != this.name)
{
String propertyName = MethodBase.GetCurentMethod().Name.SubString(4);
this.RaisePropertyChanging(propertyName);
this.name = value;
this.RaisePropertyChanged(propertyName);
}
}
}
private String name = null;
У C # 5, похоже, есть решение. С атрибутом CallerMemberName
, который может использоваться с параметрами ( Один пример в сети ).
class Employee : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
var temp = PropertyChanged;
if ( temp != null )
{
temp( this, new PropertyChangedEventArgs( caller ) );
}
}
}
Теоретически вы можете использовать MethodBase.GetCurrentMethod (). Name.Substring (4) из набора свойств. К сожалению, поиск в Google показывает, что , похоже, имеет значительное влияние на производительность . Еще две вещи, которые следует учитывать:
Не ответ на ваш вопрос, но если вы щелкните правой кнопкой мыши-> Refactor-> Rename a property, он также может переименовать соответствующие строки, включая любые строки, соответствующие имени вашего свойства.
Да, это может быть немного опасно.
Expression<Func<Program, T>>
иp=>p.Name
вместоExpression<Func<T>>
и()=>Name
? – Svish 15 July 2009 в 14:22