我需要在运行时更改接口的实现。许多类都引用了这个接口。
这是我的测试用例,它不像我期望的那样工作。 (更改界面的引用似乎不会在其使用的所有位置更新)
以下是示例:
// 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
}
为什么IDiet
实例中的Human
接口没有更新?
PS:IDiet
接口在很多类中使用,因此添加像SetDiet(IDiet diet)
这样的方法不会成为解决方案。
答案 0 :(得分:7)
当您通过此代码传递对象引用时:
Human human = new Human(diet);
将引用(对象的地址)复制到其参数:
public Human(IDiet diet)
{
_diet = diet;
}
它们是 3个不同的内存块,包含对象的相同引用:原始diet
,参数变量(diet
)和您的类属性({{ 1}})。
所以当你执行你的代码时:
_diet
此内存块现在包含对新对象(diet = new HerbivoreDiet();
)的引用,但HerbivoreDiet
内的引用仍引用旧对象。
答案 1 :(得分:1)
diet
是一个局部变量,它的值是指向内存中实际对象的指针(地址)。
如果你去diet.SomeProperty = "foo"
,你就改变了内存中的对象,这个对象随处可见。
如果你说diet = new Diet()
,你用一个指向另一个对象的新指针覆盖局部变量diet
。
Human
引用未更改,因为指针是按值传递的。他们指向的对象是相同的(直到你覆盖饮食),但指针是彼此的副本。
你应该让饮食成为一种无障碍的,非阅读的财产并改变它。或者创造一个新的人类。
答案 2 :(得分:1)
由于您已经实现了一个外观,为什么不实现第二个外观:
Human
构造其中一个并将 it 传递给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"
}
构造函数。
(1..5).each do |ind|
ThinkingSphinx::Index.define :incident, name: "incident_index_#{ind}" ... do
where "incidents.id % 5 = #{ind - 1}"
indexes ...
has ...
end
答案 3 :(得分:1)
问题:为什么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();
}
答案 4 :(得分:0)
这与接口无关。 您的代码所做的是通过值将变量传递给类构造函数,尽管该值是对实例的引用。然后,将此值复制到新创建的对象的实例的成员。然后,当您更改最初用于保存值的变量中的值时,它对您类的实例中的内部成员没有任何影响。
与int
完全相同。请考虑以下示例:
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
;
}