【问题标题】:C# records with delegate property具有委托属性的 C# 记录
【发布时间】:2020-10-18 18:08:47
【问题描述】:

在尝试使用 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

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

【问题讨论】:

    标签: c# record c#-9.0


    【解决方案1】:
    return this with { SomeAction = Bar };
    

    在原始记录上捕获Bar,而不是在更新后的记录上。而在原始记录中,SomeAction.Method.NameFoo。由于Bar返回this,而Bar是原始记录的Bar,所以第二行返回原始记录,这就解释了为什么第三行和第一行一样。

    这样改写会更容易理解:

    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;
        }
    }
    

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

    【讨论】:

    • 当然——它们是实例方法:facepalm:。这让我意识到实现我想要的另一种方法可能是使用静态方法。
    猜你喜欢
    • 2013-03-08
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多