我有一個實現屬性更改通知的基類。爲了清楚起見,我省略了實施技術細節。使用屬性更改通知和繼承
public class PersonDTO : INotifyPropertyChanged {
// in real these all have the backing field + equality check in setter + OnChanged call implementations
public string Name { get; set; }
public int Age { get; set; }
public Gender Gender { get; set; }
public PersonDTO() {
// initialize default values
// this invoke OnChanged so the object state can be maintained
Name = "New person";
Age = 30;
Gender = Gender.Female;
}
protected virtual void OnChanged(string propertyName) {
// raise PropertyChanged
}
}
我有另一個類從PersonDTO
繼承,並添加了一些屬性。
public class PersonEditorModel : PersonDTO {
public BindingList<string> Titles { get; private set; }
private readonly IRepository _repository;
public PersonEditorModel(IRepository repository) {
_repository = repository;
}
protected override void OnChanged(string propertyname) {
if (propertyName == "Gender") {
// Here is a NullReferenceException
Titles.Clear();
if (Gender == Gender.Female) {
Titles.AddRange(new[] {"Ms", "Mrs"});
else
Titles.AddRange(new[] {"Mr", "Sir"});
}
// do some other things perhaps using the _repository (which would raise a NullReferenceException again)
}
}
與該模型的問題是,在基體的構造,設置一個屬性調用改變通知,並且當所述後代尚未構造(Titles
列表爲空)的子孫類的OnChanged
方法執行。
我一直在想幾種方法。
在基礎構造函數中使用後備字段。這將修復異常,但對象狀態不會相應刷新。我始終需要一致的狀態,這意味着
Gender
和Titles
應該同步。包含一個標誌,表示該對象已構建,並檢查
OnChanged
中的該標誌。這對於這樣的簡單情況是有效的,但是如果我有3級的層次結構會怎麼樣。我需要確保在最底層的構造函數完成運行時設置該標誌,這不是微不足道的。在基類中使用工廠方法模式,在構建後我會調用類似
StartChangeTracking()
的東西。這是有問題的,因爲後代類可以有不同的構造函數參數,例如在這種情況下IRepository
服務。此外,工廠方法模式會使例如Json序列化/反序列化相當困難(我的意思是那些沒有構造函數參數的類)。
你在哪裏初始化標題?你不能簡單地在構造函數中初始化它或者像這樣:public BindingList Titles {get;私人設置; } = new BindingList (); –
3615
我在構造函數中初始化它,但問題是父構造函數更早運行。關於後一種語法,我認爲它僅適用於目前無法使用的C#6,我現在必須堅持使用.NET 4.0。另外,我不知道它在C#6中編譯的內容,可能它仍然會在構造函數中初始化,或者初始化程序將會轉到後臺字段,在這種情況下,它確實是一個解決方案。 –
@ZoltánTamási:C#6.0不僅限於.NET 4.5。即使對於.NET 2.0或更早版本,您也可以使用C#6.0。 C#6.0是一個編譯器。您仍然可以使用Visual Studio 2015並定位舊框架,並且仍然使用C#6.0功能,只要它們不需要.NET 4.5功能,請參閱http://stackoverflow.com/a/28921749/455493 – Tseng