接口不通过引用传递
Interfaces are not passed by reference
我需要在运行时更改接口的实现。这个接口被很多类.
引用
这是我的测试用例,它没有像我预期的那样工作。 (更改接口的引用似乎并没有在所有使用它的地方更新)
示例如下:
// 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)
这样的方法将不是解决方案。
当您通过此代码传递对象引用时:
Human human = new Human(diet);
引用(对象的地址)被复制到它的参数:
public Human(IDiet diet)
{
_diet = diet;
}
它们是 3 个不同的内存块,包含对对象的相同引用:您的原始 diet
、参数变量 (diet
) 和您的class 属性 (_diet
).
所以当你执行你的代码时:
diet = new HerbivoreDiet();
此内存块现在包含对新对象 (HerbivoreDiet
) 的引用,但 Human
中的内存块仍引用旧对象。
diet
是局部变量,它的值是指向内存中实际对象的指针(地址)。
如果你去diet.SomeProperty = "foo"
,你改变了内存中的对象,到处都反映出来。
如果你说 diet = new Diet()
你会用指向另一个对象的新指针覆盖局部变量 diet
。
Human
引用未更改,因为指针是按值传递的。他们指向的对象是相同的(直到你覆盖饮食),但指针是彼此的副本。
您应该将饮食设置为可访问的、非只读的 属性 并进行更改。或者创建一个新人类。
既然你已经实现了一个外观,为什么不实现第二个:
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();
}
}
构建其中之一并将它传递给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"
}
这与接口无关。
您的代码所做的是按值将变量传递给 class 构造函数,尽管该值是对实例的引用。然后,您将这个值复制到新创建的对象的实例成员中。然后,当您更改最初用于保存该值的变量中的值时,它对 class.
实例中的内部成员没有影响
与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
;
}
问题:为什么 IDiet
接口在 Human
实例中没有更新?
仅仅因为你的接口引用是通过值传递的,这意味着你在Human
class中持有的引用是指向同一个IDiet
稍后做
diet = new HerbivoreDiet();
您只需更改 Human
class 之外的引用,它仍然是自己的副本,因此没有机会更改其引用。
这是您可以实施的解决方案:
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();
}
我需要在运行时更改接口的实现。这个接口被很多类.
引用这是我的测试用例,它没有像我预期的那样工作。 (更改接口的引用似乎并没有在所有使用它的地方更新)
示例如下:
// 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)
这样的方法将不是解决方案。
当您通过此代码传递对象引用时:
Human human = new Human(diet);
引用(对象的地址)被复制到它的参数:
public Human(IDiet diet)
{
_diet = diet;
}
它们是 3 个不同的内存块,包含对对象的相同引用:您的原始 diet
、参数变量 (diet
) 和您的class 属性 (_diet
).
所以当你执行你的代码时:
diet = new HerbivoreDiet();
此内存块现在包含对新对象 (HerbivoreDiet
) 的引用,但 Human
中的内存块仍引用旧对象。
diet
是局部变量,它的值是指向内存中实际对象的指针(地址)。
如果你去diet.SomeProperty = "foo"
,你改变了内存中的对象,到处都反映出来。
如果你说 diet = new Diet()
你会用指向另一个对象的新指针覆盖局部变量 diet
。
Human
引用未更改,因为指针是按值传递的。他们指向的对象是相同的(直到你覆盖饮食),但指针是彼此的副本。
您应该将饮食设置为可访问的、非只读的 属性 并进行更改。或者创建一个新人类。
既然你已经实现了一个外观,为什么不实现第二个:
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();
}
}
构建其中之一并将它传递给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"
}
这与接口无关。 您的代码所做的是按值将变量传递给 class 构造函数,尽管该值是对实例的引用。然后,您将这个值复制到新创建的对象的实例成员中。然后,当您更改最初用于保存该值的变量中的值时,它对 class.
实例中的内部成员没有影响与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
;
}
问题:为什么 IDiet
接口在 Human
实例中没有更新?
仅仅因为你的接口引用是通过值传递的,这意味着你在Human
class中持有的引用是指向同一个IDiet
稍后做
diet = new HerbivoreDiet();
您只需更改 Human
class 之外的引用,它仍然是自己的副本,因此没有机会更改其引用。
这是您可以实施的解决方案:
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();
}