Как правильно реализовать свойство в F#?

Рассмотрим мою первую попытку, простой тип на F#, подобный следующему:

type Test() =
    inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
    let mutable prop: string = null
    member this.Prop
        with public get() = prop
        and public set value =
            match value with
                | _ when value = prop -> ()
                | _ -> 
                    let prop = value
                    this.OnPropertyChanged("Prop")

Теперь я проверяю это через C# (этот объект открыт для проекта C#, поэтому желательная семантика C# желательна):

[TestMethod]
public void TaskMaster_Test()
{
    var target = new FTest();
    string propName = null;
    target.PropertyChanged += (s, a) => propName = a.PropertyName;
    target.Prop = "newString";

    Assert.AreEqual("Prop", propName);
    Assert.AreEqual("newString", target.Prop);

    return;
}

propName правильно назначен, мой F# Setter работает, но второе утверждение не выполняется, потому что базовое значение prop не изменился Этот вид имеет смысл для меня, потому что если я удаляю mutable от prop поле, ошибка не генерируется (и это должно быть потому, что я пытаюсь изменить значение). Я думаю, что мне не хватает фундаментальной концепции.

Как правильно перевязать / изменить prop в Test класс, чтобы я мог пройти мой модульный тест?

3 ответа

Решение

Попробуй это:

type Test() =
    inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
    let mutable prop: string = null
    member this.Prop
        with public get() = prop
        and public set value =
            match value with
                | _ when value = prop -> ()
                | _ -> 
                    prop <- value
                    this.OnPropertyChanged("Prop")

Вам нужно сделать привязку изменчивой, а затем изменить ее значение в вашем установщике. В своем исходном коде вы просто создавали новую привязку (также называемую prop) внутри вашего сеттера, поэтому никаких изменений не было видно.

Как примечание, я бы, вероятно, использовал if .. then вместо match конструировать, так как это делает код более лаконичным (сопоставление паттерна особенно полезно, когда вам нужно протестировать значение с помощью нескольких сложных шаблонов). Также, public доступ по умолчанию для member, так что вы можете сделать код немного более кратким:

type Test() = 
    inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged() 
    let mutable prop : string = null 
    member this.Prop 
        with get() = prop 
        and set(value) = 
            if value <> prop then 
               prop <- value 
               this.OnPropertyChanged("Prop") 

В вашем паттерне вы связываете новое значение с

let prop = value

Когда вы связываете подобное значение с тем же именем, оно скрывает другое значение для области действия вновь объявленного. Я считаю, что вы действительно хотите сделать это:

prop <- value
Другие вопросы по тегам