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 的构造函数中。

谢谢阅读!

4

1 回答 1

4

这样做的问题是,如果我重新分配它,它不会影响 Form1 中的原件。当我输入水果 = 香蕉时,遗传学家会生成一个副本。

不,这是错误的。没有复制。

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

稍后当你决定吃原苹果时,原苹果会完好无损,但不是因为你做了一个副本。只是因为你只是对它失去了兴趣,而是抓住了一个完全不相关的水果。

那么该怎么办?

事实仍然是,您不能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);
于 2011-09-16T23:19:01.367 回答