继承接口的结构数组似乎是引用类型

时间:2018-12-21 18:57:44

标签: c# struct

我有一个名为FooBar的结构-如果它们都实现了一个称为IFoo的接口,则它们都是这样。

public interface IFoo
{
    string StrTest { get; set; }
    int NumTest { get; set; }
}

public struct Foo : IFoo
{
    public Foo(string backTest, int numTest)
    {
        StrTest = backTest;
        NumTest = numTest;
    }

    public string StrTest { get; set; }
    public int NumTest { get; set; }
}

public struct Bar : IFoo
{
    public Bar(string backTest, int numTest)
    {
        StrTest = backTest;
        NumTest = numTest;
    }

    public string StrTest { get; set; }
    public int NumTest { get; set; }
}

假设我有一个IFoo数组,在索引“ 0”处有一个Foo结构。当我将该结构移到新索引时会出现问题,例如“ 1”(将其复制)。现在,您希望它们都分开,这意味着您更改了一个,而另一个 也不应更改。

但是,我发现如果我更改了新移动的属性之一-两项都更改了……这不是class(引用类型)功能吗?

看看下面的例子:

// Create a list of "BackInterface"s - with foo and bar.
List<IFoo> arr = new List<IFoo>
{
    new Foo("A", 2),
    new Bar("B", 4)
};

// Now, place the SAME struct at index "0" (the foo) at the end - it should be copied?
arr.Add(arr[0]);

// Modify the item at the last newly-created index
arr[2].StrTest = "C";

arr[0]arr[2]的{​​{1}}现在都是StrTest

如果我只有"C"Foo的数组,那么我就没有这个问题-仅当我有Bar的数组时。我还尝试了普通数组(类型为“ IFoo)和object(没有泛型)-都没有用。

任何想法都在这里发生了什么,以及如何仍然能够同时拥有ArrayListFoo的数组,而这两者都必须实现某些东西?

2 个答案:

答案 0 :(得分:1)

通过将值类型存储在接口类型的变量中,将其装箱。接口始终是引用类型,因此需要将实现它的值类型隐式转换为接口的类型。装箱值类型是引用类型,因此您观察到引用类型的行为,因为arr[0] 实际上是引用类型

答案 1 :(得分:1)

如果没有装箱,就不能同时包含Foo和Bar和这两个结构的数组。

如果将结构强制转换为接口,则会得到拳击,这是在创建List 然后将结构放入其中时发生的。通过执行操作,您可以看到您的结构已成为引用类型

bool test = arr[0].GetType().IsValueType; 

创建arr后:对于List 为false,对于List 为true。

有一些解决方法,例如有两个数组,一个数组用于Foo,一个数组用于Bar,然后使用另一个数组对这两个数组进行索引。但这太可怕了。有关更多信息,请参见this earlier Stack Overflow answer

由于所有这些,将接口放置在结构上并不是一个好主意:结构旨在是轻量级的东西,它们可以存在于堆栈中。如果您需要这种行为,最好使用类。