接口不是通过引用传递的
本文关键字:引用 接口 | 更新日期: 2023-09-27 17:50:33
我需要在运行时更改接口的实现。这个接口被许多类引用。
这是我的测试用例,它没有像我预期的那样工作。(改变接口的引用似乎不会在所有使用它的地方更新)
示例如下:
// interface to change at runtime
interface IDiet
{
void Eat();
}
class CarnivoreDiet : IDiet
{
public void Eat()
{
Debug.WriteLine("Eat chicken");
}
}
class HerbivoreDiet : IDiet
{
public void Eat()
{
Debug.WriteLine("Eat spinach");
}
}
class Human : IDiet
{
private readonly IDiet _diet;
public Human(IDiet diet)
{
_diet = diet;
}
public void Eat()
{
_diet.Eat();
}
}
void Main()
{
IDiet diet = new CarnivoreDiet();
Human human = new Human(diet);
human.Eat();
// outputs "Eat chicken"
diet = new HerbivoreDiet();
human.Eat();
// still outputs "Eat chicken" even if i changed the reference of IDiet interface
}
为什么在Human
实例中IDiet
接口没有更新?
PS: IDiet
接口在很多类中使用,所以增加SetDiet(IDiet diet)
这样的方法是不能解决的。
当您通过以下代码传递对象引用时:
Human human = new Human(diet);
引用(对象的地址)被复制到它的形参:
public Human(IDiet diet)
{
_diet = diet;
}
它们是3块不同的内存,包含对对象的相同引用:您的原始diet
,参数变量(diet
)和类属性(_diet
)。
所以当你执行你的代码时:
diet = new HerbivoreDiet();
这个内存块现在包含对新对象(HerbivoreDiet
)的引用,但是Human
内部的内存块仍然引用旧对象。
既然您已经实现了一个facade,为什么不实现第二个呢:
class ChangableDiet : IDiet
{
private IDiet _diet;
public ChangableDiet (IDiet diet)
{
_diet = diet;
}
public Diet Diet { get { return _diet;} set { _diet = value; } }
public void Eat()
{
_diet.Eat();
}
}
构造其中一个,并将it传递给Human
构造函数。
void Main()
{
IDiet diet = new CarnivoreDiet();
var changable = new ChangableDiet(diet)
Human human = new Human(changable );
human.Eat();
// outputs "Eat chicken"
changable.Diet = new HerbivoreDiet();
human.Eat();
// outputs "Eat spinach"
}
diet
是一个局部变量,它的值是指向内存中实际对象的指针(地址)。
如果你去diet.SomeProperty = "foo"
,你改变了内存中的对象,这是处处反映。
如果输入diet = new Diet()
,则用指向另一个对象的新指针覆盖局部变量diet
。
Human
引用没有改变,因为指针是按值传递的。它们指向的对象是相同的(除非您覆盖diet),但指针是彼此的副本。
你应该将diet设置为一个可访问的非只读属性,并对其进行修改。或者创造一个新的人
问题:为什么IDiet
接口不更新Human
实例内?
Human
类中持有的引用是指向同一个IDiet
的副本之后做
diet = new HerbivoreDiet();
您只需更改Human
类之外的引用,该类仍然保留自己的副本,因此没有机会更改其引用。
这是一个你可以实现的解决方案:
public interface IProvider<T>
{
public T Current {get; set;}
}
public class DietProvider : IProvider<IDiet>
{
public IDiet Current {get; set;}
}
class Human : IDiet
{
private readonly IProvider<IDiet> _dietProvider;
public Human(IProvider<IDiet> dietProvider)
{
_dietProvider = dietProvider;
}
public void Eat()
{
_dietProvider.Current.Eat();
}
}
void Main()
{
IProvider<IDiet> dietProvider= new DietProvider { Current = new CarnivoreDiet()};
Human human = new Human(dietProvider);
human.Eat();
// outputs "Eat chicken"
dietProvider.Current = new HerbivoreDiet();
human.Eat();
}
这与接口无关。您的代码所做的是按值将变量传递给类构造函数,尽管该值是对实例的引用。然后将该值复制到新创建对象实例的成员中。然后,当您更改最初用于保存该值的变量中的值时,它不会对类实例中的内部成员产生影响。
它将与 int
s完全相同。考虑以下示例:
class MyClass {
private int mInt;
public MyClass(int theInt) {
mInt = theInt;
}
public int GetTheInt() { return mInt; }
}
void Main()
{
int anInt = 5;
MyClass MyInstance(anInt);
anInt = 10;
if(MyInstance.GetTheInt() == anInt)
// Will never happen
;
}