我有一个名为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]
的StrTest
现在都是"C"
。
如果我有一个只有Foo
或Bar
的数组,我就没有这个问题——只有当我有IFoo
的数组时。我还尝试过普通数组(类型为"object
")和ArrayList
(没有泛型),但都不起作用
知道这里发生了什么吗,,以及如何仍然能够同时拥有Foo
和Bar
的数组,两者都必须有某个实现吗
如果没有所看到的装箱,就不可能同时拥有Foo和Bar这两种结构的数组。
如果将结构强制转换为接口,则会出现装箱,当创建List<IFoo>然后把你的结构放进去。你可以通过看到你的结构已经变成了引用类型
bool test = arr[0].GetType().IsValueType;
在您创建arr之后:对于List<IFoo>并且对于List<Foo>。
有一些变通方法,比如有两个数组——一个用于Foo,一个用于Bar,然后用另一个数组对这两个数组进行索引。但这太可怕了。有关更多信息,请参阅前面的"堆栈溢出"回答。
由于所有这些,通常在structs上放置接口不是一个好主意:structs旨在成为栈上的轻量级对象。如果你需要这种行为,你最好使用类。
通过将值类型存储在接口类型的变量中,它会被装箱。接口总是引用类型,因此隐式地将实现它的值类型转换为接口的类型需要将其装箱。装箱的值类型是引用类型,所以您观察的是引用类型行为,因为arr[0]
实际上是引用类型。