Какъв вид компилаторска магия ни трябва повече?

Разработвам модели за изглед на партиди, които са:

1) Всички трябва да внедрят INotifyPropertyChanged, за да могат да се свързват с потребителския интерфейс.

2) Създателите на свойства трябва да повдигнат PropertyChanged при промяна.

3) Събитието PropertyChanged трябва да предоставя правилно име на свойство.

Ако вие (като мен) искате да напишете нещо подобно:


public string Name 
{
  get 
  { 
    return _name; 
  }
  set 
  { 
    if (_name != value) 
    {
      _name = value;
      RaisePropertyChanged("Name");
    }
  }
} 

След това преработете този метод по този начин и понякога забравяте да актуализирате литерала на името на свойството:


string _fundName;
public string FundName 
{
  get 
  { 
    return _fundName; 
  }
  set 
  { 
    if (_fundName != value) 
    {
      _fundName = value;
      RaisePropertyChanged("Name");
    }
  }
} 

И след това отделете един ден за отстраняване на грешки защо потребителският ви интерфейс не се опреснява и обвързването на данни не работи правилно.

Тогава всичко, от което се нуждаем, е някаква магия.

Ами ако просто трябва да напиша това:


[Magic] // implicit transformation
public string FundName { get; set; }

или ако имам много имоти:


[Magic]
public class MyViewModel
{
  public string FundName { get; set; }
  public string FundType { get; set; }

  [NoMagic] // suppress transformation
  public int InternalId { get; set; }
}

Така че току-що разработих задача на MSBuild, за да направя тази магия след изграждането (http://kindofmagic.codeplex.com ).

Въпросът е какъв вид магическа последваща обработка бихте искали повече?

Има ли смисъл автоматичното внедряване на INotifyPropertyChanging?


person Lex Lavnikov    schedule 01.12.2010    source източник
comment
Какво ще кажете за създаването на същото нещо за INotifyPropertyChanging?   -  person Matěj Zábský    schedule 01.12.2010
comment
@CommanderZ прилагате ли и използвате ли INotifyPropertyChanging? Ако да за какво? може би искате да коментирате stackoverflow.com/questions/3835788/   -  person Simon    schedule 02.12.2010


Отговори (5)


Ако ще имаме фантастично генериране на код, мисля, че бих предпочел начин за по-лесно генериране на DependancyProperties. Фрагментът, който използвам, със сигурност е полезен, но не съм фен на това колко объркано изглежда кодът, когато имате on-changed и принудителни обратни извиквания и опции за метаданни. Може би ще опитам да направя макет на проба след работа.

Редактиране: Е, ето една концепция. Ще изглежда много по-умно, ако подадете анонимни методи към атрибутите, но все пак е стъпка напред.

Преди:

[DpDefault("The Void")]
[DpCoerce(new CoerceValueCallback(MainWindow.CoerceAddress))]
[DpChanged(new PropertyChangedCallback(MainWindow.ChangeAddress1))]
[DpChanged(new PropertyChangedCallback(MainWindow.ChangeAddress2))]
[DpOptions(FrameworkPropertyMetadataOptions.Inherits)]
public string Address {
    get { return Dp.Get<string>(); }
    set {
        if (Dp.Get<string>() != value) {
            Dp.Set(value);
            PostOffice.SendMailToTheBoss("I moved!");
        }
    }
}

След:

public string Address {
    get { return (string)GetValue(AddressProperty); }
    set {
        if ((string)GetValue(AddressProperty) != value) {
            SetValue(AddressProperty, value);
            PostOffice.SendMailToTheBoss("I moved!");
        }
    }
}

public static readonly DependencyProperty AddressProperty =
    DependencyProperty.Register("Address", typeof(string), typeof(MainWindow),
        new FrameworkPropertyMetadata((string)"The Void",
            FrameworkPropertyMetadataOptions.Inherits,
            new PropertyChangedCallback(MainWindow.ChangeAddress1)
                + new PropertyChangedCallback(MainWindow.ChangeAddress2),
            new CoerceValueCallback(MainWindow.CoerceAddress)));

Обикновено ще се използва само атрибутът „DpDefault“, но дори и да не прави кода по-кратък, със сигурност го прави по-ясен. Ето един по-типичен пример:

Преди:

[DpDefault("The Void")]
public string Address { get; set; }

След:

public string Address {
    get { return (string)GetValue(AddressProperty); }
    set { SetValue(AddressProperty, value); }
}

public static readonly DependencyProperty AddressProperty =
    DependencyProperty.Register("Address", typeof(string), typeof(MainWindow),
        new UIPropertyMetadata((string)"The Void"));
person YotaXP    schedule 01.12.2010
comment
Добра идея. Можем да генерираме свойство на зависимост от нормално, като извлечем сетер в манипулатора OnDependencyPropertyChanged. И генерирайте статично поле само за четене на DependencyProperty с правилно извлеченото име, ако то не съществува. - person Lex Lavnikov; 01.12.2010
comment
Редактира отговора с макетна концепция за това как може да изглежда трансформацията на кода. - person YotaXP; 02.12.2010

Опитайте тази

http://code.google.com/p/notifypropertyweaver/

  • Не са необходими атрибути
  • Не се изискват препратки
  • Не се изисква базов клас

Ето статията в моя блог за това

http://codesimonsays.blogspot.com/2010/11/attempting-to-solve-inotifypropertychan.html

Той поддържа атрибутите, които поискате

  • NotifyPropertyAttribute (уведомяване за свойство)
  • NotifyForAllAttribute (уведомяване за всички свойства на тип)
  • NotifyIgnoreAttribute (не уведомявайте за свойство или тип)
  • AlsoNotifyFor (Позволява инжектирането на код за уведомяване, който сочи към различно свойство)

Въпреки че те са опция и са предназначени за фина настройка. Повечето инжекции се извършват по конвенция чрез анализ на съществуващия IL.

person Simon    schedule 01.12.2010
comment
Вероятно заради извънземния хостинг на проекти ;) - person Lex Lavnikov; 02.12.2010
comment
Между другото, харесва ми идеята с премахването на препратки. Дойдох само за премахване на атрибути ;) - person Lex Lavnikov; 02.12.2010
comment
@Lex радвам се, че ти харесва. Моят подход подобен ли е на това, което планирахте? Някаква друга функция, за която се сещате? - person Simon; 02.12.2010
comment
@Lex Аз също подкрепям да имате свои собствени атрибути. Вижте Нямате препратка във вашия проектен файл code.google.com/p/notifypropertyweaver/wiki/ - person Simon; 02.12.2010

„Магия“ почти винаги е ужасно име за метод, свойство или променлива на всеки език. Трябва да преименувате атрибута на нещо по-описателно. Представете си, че сте просто случаен интернет пешеходец и се натъквате на частичен код с атрибут „Магия“, какво ви казва това за кода? Точно нищо :)

Все пак ще пробвам вашия код, има потенциал да спести доста време. Това определено трябва да е част от .NET.

person Matěj Zábský    schedule 01.12.2010
comment
Атрибут, наречен Magic, определено ще привлече вниманието ми. Но аз съм съгласен с теб. Търсите по-добро име, някакви идеи? - person Lex Lavnikov; 01.12.2010
comment
Това всъщност не е отговор. - person Simon; 02.12.2010
comment
Какво не е наред с [NotifyPropertyChanged]int SomeProperty {get; комплект;} - person Matěj Zábský; 02.12.2010

Нещо, което може да направи живота ви малко по-лесен, е това... (Взех го от Caliburn Micro).

 public virtual void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property) {
            NotifyOfPropertyChange(property.GetMemberInfo().Name);
        }

Това ви позволява да направите следното..

NotifyOfProperyChange(() => this.PropertyName);

Това ще подчертае всички проблеми с кода по време на проектиране, а не по време на изпълнение.

Caliburn Micro е страхотна малка рамка, която трябва да разгледате, тя премахва толкова голяма част от окабеляването, свързано с MVVM и Silverlight / WPF!

person BenjaminPaul    schedule 01.12.2010
comment
И аз съм ползвал C.M. Но, честно казано, това са много пропилени цикли на процесора, само за да получите ПРАВИЛНО име на свойството. Основната причина зад проекта KindOfMagic е да го направи възможно най-ефективен и нулево въвеждане за потребителите. - person Lex Lavnikov; 01.12.2010

Това вече може да се направи с помощта на AOP (Аспектно ориентирано програмиране) инструмент като PostSharp: http://www.richard-banks.org/2009/02/aspect-oriented-programming.html (с v1.x) http://www.sharpcrafters.com/solutions/ui#data-binding (с v2.0)

Използвах PostSharp за внедряване на INPC в няколко проекта и се получи доста добре, кодът е много по-чист и поддържаем (добавя няколко секунди за време за компилиране)

person Catalin DICU    schedule 01.12.2010
comment
Опитах PostSharp за INPC преди месец, но генерираният IL код за сетери беше толкова раздут и грозен (използвах Reflector). Моето мнение е, че общите AOP инструменти въвеждат твърде големи разходи за този малък конкретен проблем. - person Lex Lavnikov; 01.12.2010
comment
Потвърдихте ли това мнение с тестове за ефективност? Според моя опит режийните разходи, въведени от AOP в този случай, не се усещат. - person Robert Rossney; 01.12.2010
comment
re postsharp bloat инжектира приблизително 150 реда код във всяко свойство. - person Simon; 02.12.2010
comment
@Робърт, просто имам нужда от правилна проверка на стара-нова стойност и събитие за повишаване, ако е различно. Не ми трябват нито Starship Enterprise, нито Battlestar Galactica. - person Lex Lavnikov; 02.12.2010
comment
@Simon, той може да инжектира 10 000 реда код във всяко свойство и няма да ме притеснява, стига потребителите да не забелязват разлика в производителността. Въпреки това не прекарвам много (или всъщност никакво) време в ровене в моите сетери с Reflector, така че може би правя нещо нередно. Или дясно. - person Robert Rossney; 02.12.2010
comment
@Rob Не съм загрижен за последиците от производителността. Притеснявам се, че размерът на моето сглобяване е няколко пъти по-голям поради 150 реда код за всеки комплект. - person Simon; 03.12.2010
comment
@Rob Предполагам, че се свежда до компромиси. Postsharp е чудесен инструмент, но стойностното предложение за използването му за уведомяване за собственост е размито поради проблемите, споменати по-горе. - person Simon; 03.12.2010