我有一个名为Foo
和Bar
的结构-如果它们都实现了一个称为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
(没有泛型)-都没有用。
任何想法都在这里发生了什么,以及如何仍然能够同时拥有ArrayList
和Foo
的数组,而这两者都必须实现某些东西?
答案 0 :(得分:1)
通过将值类型存储在接口类型的变量中,将其装箱。接口始终是引用类型,因此需要将实现它的值类型隐式转换为接口的类型。装箱值类型是引用类型,因此您观察到引用类型的行为,因为arr[0]
实际上是引用类型。
答案 1 :(得分:1)
如果没有装箱,就不能同时包含Foo和Bar和这两个结构的数组。
如果将结构强制转换为接口,则会得到拳击,这是在创建List
bool test = arr[0].GetType().IsValueType;
创建arr后:对于List
有一些解决方法,例如有两个数组,一个数组用于Foo,一个数组用于Bar,然后使用另一个数组对这两个数组进行索引。但这太可怕了。有关更多信息,请参见this earlier Stack Overflow answer。
由于所有这些,将接口放置在结构上并不是一个好主意:结构旨在是轻量级的东西,它们可以存在于堆栈中。如果您需要这种行为,最好使用类。