C# 记录委托 属性

C# records with delegate property

在试验 C# 9 记录时,我遇到了一个相当奇怪的行为。我的记录是这样的:

record MyRecord(Func<MyRecord> SomeAction, string Name)
{
    public MyRecord(string name) : this(null, name) 
    {
        SomeAction = Foo;
    }

    // Foo returns 'this' with SomeAction changed to Bar
    MyRecord Foo()
    {
        Console.WriteLine("Foo: " + SomeAction.Method.Name);
        return this with { SomeAction = Bar };
    }

    MyRecord Bar()
    {
        Console.WriteLine("Bar: " + SomeAction.Method.Name);
        return this;
    }
}

我是这样使用的:

class Program
{
    static void Main(string[] args)
    {
        var r = new MyRecord("Foo");
        Console.WriteLine(r.ToString());
        r = r.SomeAction();
        r = r.SomeAction();
        r = r.SomeAction();
    }
}

我预期的输出是

Foo: Foo
Bar: Bar
Bar: Bar

然而,我得到的实际输出:

Foo: Foo
Bar: Foo 
Foo: Foo

这是一个错误还是我遗漏了什么?

return this with { SomeAction = Bar };

捕获 Bar 原始记录,而不是更新的记录。而在原始记录上,SomeAction.Method.NameFoo。由于Barreturnsthis,而Bar是原始记录的Bar,第二行returns是原始记录,这就解释了为什么第三行同第一行

这样改写会更容易理解:

class Program
{
    static void Main(string[] args)
    {
        var r = new MyRecord("Foo");
        Console.WriteLine(r.ToString());
        var r1 = r.SomeAction(); // calls r.Foo, returns new instance of record, capturing r.Bar
        var r2 = r1.SomeAction(); // calls r.Bar, and returns r.
        var r3 = r2.SomeAction(); // calls r.Foo, returns new instance of record, capturing r.Bar
    }
}

要获得预期的行为,您必须执行以下操作:

record MyRecord(Func<MyRecord> SomeAction, string Name)
{
    public MyRecord(string name) : this(null, name) 
    {
        SomeAction = Foo;
    }

    // Foo returns 'this' with SomeAction changed to Bar
    MyRecord Foo()
    {
        Console.WriteLine("Foo: " + SomeAction.Method.Name);
        MyRecord updated = null;
        updated = this with { SomeAction = () => updated.Bar() };
        return updated;
    }

    MyRecord Bar()
    {
        Console.WriteLine("Bar: " + SomeAction.Method.Name);
        return this;
    }
}

但是我不推荐这种方法 - 它很难遵循。