【问题标题】:C# Float Wrapper For Use In Observer Pattern用于观察者模式的 C# 浮点包装器
【发布时间】:2019-01-26 18:03:59
【问题描述】:

我正在尝试在 C# 中实现可观察的本机数据类型(float、int、string、List)。我应该补充一点,我是 C# 的新手,并且来自 C++ 背景。

我的第一个想法是有一个像这样的可观察界面:

public interface IObservable {

    void registerObserver(IObserver observer);

    void deregisterObserver(IObserver observer);

    void notifyObservers();
}

然后为本地数据类型(例如浮点数)创建一个包装器,它重载了运算符,因此它(大部分)可以无缝使用:

Float f1 = new Float(0);
Float f2 = f1 + 2;

这必须是一个抽象基类,因为接口不能重载运算符。

然后我想创建一个 ObservableFloat,它结合了这两种想法,但在其状态发生任何变化时都会调用 notifyObservers。使用它的类会将其视为一个 Float,并且不知道它在内部也是一个 Observable。

为此,我通常会重载赋值运算符,而不是这样做:

return new Float(f1.value + f2.value);

它会修改第一个实例并返回它。但是由于赋值似乎总是改变引用,所以我会在第一次赋值操作时丢失我的 observable 及其观察者列表,对吗?

我发现这篇文章使用 C# 中的事件实现了观察者:link 这段代码:

private State _state;

public State MyState
{
    get { return _state; }
    set
    {
        if (_state != value)
        {
            _state = value;
            Notify();
        }
    }
}

基本上是我想要的:当 State 变量被分配一个新值时,它会执行分配并调用一个函数。有什么方法可以在不让 using 类(示例中为 Product)知道变量是 Observable 的情况下实现这一点?

【问题讨论】:

    标签: c# events operator-overloading observer-pattern assignment-operator


    【解决方案1】:

    我认为你应该使用类似 fluent 的东西来获得灵活性,而不是重载原始类型及其运算符只是将它们注入某个地方它不属于:

    public interface INumeric
    {
        INumeric Add(INumeric num);
        INumeric Sub(INumeric num);
        INumeric Mul(INumeric num);
        INumeric Div(INumeric num);   
    }
    

    所以,例如,如果你想复制原始类型的行为,你会在里面得到类似的东西:

    public INumeric Sub(INumeric b)
    {
        var a = this;
        return new Numeric(a.Value-b.Value);//obviuously, no notify here
    }
    

    如果您想以流畅的方式使用实例并通知观察者:

    public INumeric Sub(INumeric b)
    {
        var a = this;
        a.Value = a.Value - b.Value;//notify 'a' observers or whatever here.
        return a;
    }
    

    在代码中它看起来像这样,并且不会在赋值时中断,但要注意下面的小技巧,在使用引用时可能会让您感到困惑(omg 将无法调试):

    var a = new Numeric(10);
    var b = new Numeric(2);
    
    a = a.Sub(b)//10 - 2 = 8
         .Add(a)//8 + 8 = 16
         .Add(b);//16 + 2 = 18
    

    原始形式:

    a = a - b + a + b; //10 - 2 + 10 + 2 = 20
    

    PS:

    如您所见,重载原始类型是个坏主意。它们在本质上与可以轻松打乱您的整个逻辑的参考文献大相径庭。

    【讨论】:

    • 对,这是我想的另一个选择。那时我将不得不走这条路。谢谢!
    • 既然这个实现已经清楚地表明您正在使用一个对象,那么让所有 INumeric 返回 void 以便您一眼就能看出他们正在修改该对象不是更清楚吗?跨度>
    • 是的,如果你想展示那个特定的方面会更清楚。但是,我只为方法链接添加了 INumeric 的返回。它将代码简化为编写描述“do that, then that, then another”等动作的精确句子的代码,而无需过多重复的样板代码。更多在这里 - stackoverflow.com/questions/1119799/method-chaining-in-c-sharp
    猜你喜欢
    • 2021-11-22
    • 2010-10-10
    • 2013-12-30
    • 2016-02-20
    • 2023-04-10
    • 1970-01-01
    • 2013-10-28
    • 2014-05-26
    • 1970-01-01
    相关资源
    最近更新 更多