如何在另一个类中重新分配引用类型并使更改保持原始状态?

发布于 2024-12-05 07:32:12 字数 1375 浏览 0 评论 0原文

这是我所要求的一个相当人为的示例:

public partial class Form1 : Form
{
    private Fruit fruit;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        fruit = new Apple();

        Geneticist geneticist = new Geneticist(fruit);

        // Later on in program..

        geneticist.Engineer();

        Console.WriteLine(fruit.Color);

        // Still red because a copy of fruit was made in Geneticist class.
    }
}

class Fruit
{
    public string Color { get; set; }
}

class Apple : Fruit
{
    public Apple()
    {
        Color = "Red";
    }
}

class Banana : Fruit
{
    public Banana()
    {
        Color = "Yellow";
    }
}

class Geneticist
{
    private Fruit fruit;
    private Banana banana;

    public Geneticist(Fruit fruit)
    {
        this.fruit = fruit;
        this.banana = new Banana();
    }

    public void Engineer()
    {
        fruit = banana;
    }
}

基本上,我在主窗体中存储了一个水果作为成员变量。我希望能够将它传递给我的遗传学家课程,然后让它重新分配值。

当我输入 fruit = Banana; 遗传学家中的水果不再指向 Form1 水果,而是指向遗传学家中的本地副本。我想,我正在寻找一种模拟 ref 关键字的方法,如果我重新分配遗传学家水果,Form1 水果也会随着更改而更新。

我想我可以制作一个水果包装纸并将其传递出去,但这似乎有点黑客。另外,我可以让 Engineer 方法引发一个事件,以便主窗体可以重新分配值,但必须在程序的许多部分执行此操作似乎也有点混乱。

另外,我无法使用 ref 关键字,因为我稍后修改它,而不是在 Geneticist 的构造函数中修改它。

感谢您的阅读!

Here is a rather contrived example of what I am asking:

public partial class Form1 : Form
{
    private Fruit fruit;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        fruit = new Apple();

        Geneticist geneticist = new Geneticist(fruit);

        // Later on in program..

        geneticist.Engineer();

        Console.WriteLine(fruit.Color);

        // Still red because a copy of fruit was made in Geneticist class.
    }
}

class Fruit
{
    public string Color { get; set; }
}

class Apple : Fruit
{
    public Apple()
    {
        Color = "Red";
    }
}

class Banana : Fruit
{
    public Banana()
    {
        Color = "Yellow";
    }
}

class Geneticist
{
    private Fruit fruit;
    private Banana banana;

    public Geneticist(Fruit fruit)
    {
        this.fruit = fruit;
        this.banana = new Banana();
    }

    public void Engineer()
    {
        fruit = banana;
    }
}

Basically, I have a fruit stored as a member variable in my main form. I want to be able to pass it to my Geneticist class and later on have it re-assign the value.

When I type fruit = banana; the fruit in geneticist no longer points to the the Form1 fruit but instead to the local copy in Geneticist. I am looking for a way to simulate the ref keyword, I suppose, where if I re-assign the geneticist fruit the Form1 fruit is also updated with the change.

I suppose I could create a wrapper of fruit and pass that around instead but that seems a bit hackish. Also I could have the Engineer method raise an event so that the main form can re-assign the value but having to do that at many parts of my program seems a bit messy as well.

Also, I cannot use the ref keyword because I modify it later on, not in the constructor of Geneticist.

Thanks for reading!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

好菇凉咱不稀罕他 2024-12-12 07:32:12

这样做的问题是,如果我重新分配它,它不会影响
原件为Form1。当我输入“fruit =”时,Geneticist 中会生成一份副本
香蕉。

不,这是错误的。不会进行任何复制。

发生的情况是,您用对 Banana 的引用覆盖了您手头的 Apple 的引用。就好像你有一个苹果放在你的口袋里,你拿着它一会儿后,你把它放在地上,拿起一根香蕉,然后把它放进你的口袋里。

当您稍后决定吃原始苹果时,它会完好无损,但不是因为您复制了。只是因为你对它失去了兴趣,而是得到了一种完全不相关的水果。

那么该怎么办?

事实仍然是,您无法使用引用语义将 Fruit 参数作为一个整体进行修改(CLR 不允许将引用存储为类成员,因为你自己也说过了)。

如果您希望Geneticist 修改Fruit 引用,那么您必须围绕它创建一个包装器。但最实用的解决方案是让调用代码与 Geneticist 合作:

class Geneticist
{
    private Fruit fruit;
    private Banana banana;

    public Geneticist(Fruit fruit)
    {
        this.fruit = fruit;
        this.banana = new Banana();
    }

    public Fruit Engineer()
    {
        fruit = banana;
        return fruit; // return the new value
    }
}

调用代码:

fruit = new Apple();

Geneticist geneticist = new Geneticist(fruit);
fruit = geneticist.Engineer(); // use the return value this way
Console.WriteLine(fruit.Color);

另一种可行的方法

Geneticist 怎么样?知道如何修改水果本身吗?

class Geneticist
{
    private Fruit fruit;

    private readonly Banana banana;

    private readonly Action<Fruit> engineer;

    public Geneticist(Fruit fruit, Action<Fruit> engineer)
    {
        this.fruit = fruit;
        this.banana = new Banana();
        this.engineer = engineer;
    }

    public void Engineer()
    {
        this.engineer(this.banana);
    }
}

以及调用代码:

Fruit fruit = new Apple();
Geneticist geneticist = new Geneticist(fruit, f => { fruit = f; });
geneticist.Engineer();
Console.WriteLine(fruit.Color);

The problem with this is that if I re-assign it, it doesn't affect the
original in Form1. A copy is made in Geneticist when I type fruit =
banana.

No, this is wrong. No copy is made.

What happens is that you overwrite the reference you have at hand of the Apple with a reference to a Banana. It's as if you are given an apple to put in your pocket and after holding on to it for a little while, you leave it on the ground, pick up a banana, and place it in your pocket.

When at some later point you decide to eat the original apple will be intact, but not because you made a copy. Only because you just lost interest in it and got hold of a totally unrelated fruit instead.

So what to do?

The fact remains that you cannot modify the Fruit parameter as a whole with reference semantics (the CLR does not allow refs to be stored as class members, as you yourself have said).

If you want Geneticist to modify the Fruit reference, then you do have to create a wrapper around it. But the most practical solution would be to have the calling code cooperate with Geneticist:

class Geneticist
{
    private Fruit fruit;
    private Banana banana;

    public Geneticist(Fruit fruit)
    {
        this.fruit = fruit;
        this.banana = new Banana();
    }

    public Fruit Engineer()
    {
        fruit = banana;
        return fruit; // return the new value
    }
}

And the calling code:

fruit = new Apple();

Geneticist geneticist = new Geneticist(fruit);
fruit = geneticist.Engineer(); // use the return value this way
Console.WriteLine(fruit.Color);

Another workable approach

What about letting the Geneticist know how to modify the fruit themselves?

class Geneticist
{
    private Fruit fruit;

    private readonly Banana banana;

    private readonly Action<Fruit> engineer;

    public Geneticist(Fruit fruit, Action<Fruit> engineer)
    {
        this.fruit = fruit;
        this.banana = new Banana();
        this.engineer = engineer;
    }

    public void Engineer()
    {
        this.engineer(this.banana);
    }
}

And the calling code:

Fruit fruit = new Apple();
Geneticist geneticist = new Geneticist(fruit, f => { fruit = f; });
geneticist.Engineer();
Console.WriteLine(fruit.Color);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文