Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 接口不是通过引用传递的_C#_Asp.net_Pointers_Reference - Fatal编程技术网

C# 接口不是通过引用传递的

C# 接口不是通过引用传递的,c#,asp.net,pointers,reference,C#,Asp.net,Pointers,Reference,我需要在运行时更改接口的实现。这个接口被许多类引用 这是我的测试用例,它没有像我期望的那样工作。(更改接口的引用似乎不会在其使用的所有位置更新) 以下是一个例子: // interface to change at runtime interface IDiet { void Eat(); } class CarnivoreDiet : IDiet { public void Eat() { Debug.WriteLine("Eat chicken");

我需要在运行时更改接口的实现。这个接口被许多类引用

这是我的测试用例,它没有像我期望的那样工作。(更改接口的引用似乎不会在其使用的所有位置更新)

以下是一个例子:

// 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
)和类属性(
\u diet

因此,当您执行代码时:

diet = new HerbivoreDiet();

此内存块现在包含对新对象的引用(
herbivoediet
),但
Human
中的内存块仍然引用旧对象。

diet
是一个局部变量,它的值是指向内存中实际对象的指针(地址)

如果您转到diet.SomeProperty=“foo”,则会更改内存中的对象,该对象会反映在所有位置

如果您说
diet=new diet()
则使用指向另一个对象的新指针覆盖局部变量
diet

Human
引用保持不变,因为指针是按值传递的。他们指向的对象是相同的(直到你覆盖饮食),但指针是彼此的副本


您应该使diet成为一个可访问的、非只读的属性,并对其进行更改。或者创建一个新的人员。

既然已经实现了一个外观,为什么不实现第二个呢:

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"
}

这与接口无关。 代码所做的是通过值将变量传递给类构造函数,尽管该值是对实例的引用。然后将该值复制到新创建对象实例的成员。然后,当您更改最初用于保存该值的变量中的值时,它对类实例中的内部成员没有影响

这与
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
   ;
}

问题:为什么
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();
}
公共接口IProvider
{
公共T当前{get;set;}
}
公共类提供程序:IProvider
{
公共IDiet当前{get;set;}
}
班级:IDiet
{
私有只读IProvider\u提供程序;
公共人员(IProvider提供程序)
{
_dietProvider=dietProvider;
}
公共图书馆
{
_dietProvider.Current.Eat();
}
}
void Main()
{
IProvider dietProvider=新的dietProvider{Current=新的CarnivoreDiet()};
人类=新人类(饮食提供者);
人类。吃();
//“吃鸡肉”
dietProvider.Current=new HerbivoreDiet();
人类。吃();
}

你期望什么,你观察到什么行为?“不更新”是什么意思?参考是只读的;一旦你设置了它,引用应该是不可变的。因为人类有一个引用的副本(
\u diet
),而你正在修改引用的另一个副本(
diet
)@Rahul这本质上是构造函数注入。我不认为IoC或DI会改变任何东西。接口在这里是无关紧要的——我认为你基本上需要重新审视C#的工作方式。特别是,您似乎希望
human.\u diet
字段链接到
diet
局部变量。不是-将
diet
的值复制到
diet
参数中,然后将该参数复制到
\u diet
字段中。以后对
diet
局部变量的更改是不相关的。您可能需要读取并将参数复制到字段:-)三个不同的内存块,其中一个具有非常有限的持续时间(参数)@xanatos:是的,我错过了。这是一个错误,但这是这个问题的主要原因。