我需要将结构作为值类型传递给列表。 假设我有一个派生自接口的结构:
interface IFoo
{
...
}
struct Foo1 : IFoo { ... }
struct Foo2 : IFoo { ... }
//Some other class which contains this:
List<IFoo> listOfFoo;
我知道如果我这样做:IFoo foo = new Foo1()
,它会将值转换为参考(拳击)。
Foo1
或Foo2
添加到List<IFoo>
,结构是否会作为参考传递? List<object>
是否安全且仅添加这些结构,或者在类上进行MemberwiseClone会更好吗? 我也在寻找效率,因为这将用于瓦片地图中的碰撞检测。
答案 0 :(得分:5)
结构将被装箱。为什么他们不是? List<IFoo>
中的每个值都必须是IFoo
,因此您添加的每个结构实例都会通过装箱进行转换。
结构仍然是盒装的,因为object
也是引用类型。在您的方案中,除非您将列表声明为特定值类型(List<Foo1>
或List<Foo2>
),否则根本无法避免装箱。
一般来说,使用结构来提高效率&#34;根本不是一件简单或明显的事情。特别是,简单地在struct
中放置,否则您写class
并不能保证您的代码表现更好。首先以明显的方式编写代码(这里显而易见:使用类),然后确定(通过分析)是否需要优化它,如果需要,如何优化。
答案 1 :(得分:2)
如果你有一个列表我是一个界面,你添加了 F1 和 F2 类型的元素,其中两个都实现我接口,然后当您从List中检索任何两个元素时,您可以使用关键字** is **检查引用的类型,并继续将适当的强制转换应用于从List获得的元素
例如:
struct Foo1 : IFoo {...}
struct Foo2 : IFoo {...}
List<IFoo> listOfFoo = new List<IFoo>();
IFoo foo1 = new Foo1();
IFoo foo2 = new Foo2();
listOfFoo.Add(foo1);
listOfFoo.Add(foo2);
// lets retrieve the first element and check if it's a Foo1 value type
if(listOfFoo[0] is Foo1){
// cast element from List to Foo1
Foo1 foo = (Foo1) listOfFoo[0];
}
由于我们正在处理结构,当List中的元素被转换回原始值类型时,它应该是unboxed。但是太多的拆箱和装箱可以达到性能,因为你想要执行碰撞检测之类的东西,这可能会给你带来低性能。
您是否必须使用结构?由于对存储的盒装对象执行操作,对变量进行的拳击更改可能无法正常运行,并且正如我所提到的,太多拳击可能会给您带来不良结果。
在我看来,使用MemberwiseClone的课程会更好。
您可以阅读MSDN上的this文章,其中详细说明了结构和类的优缺点,这可能有助于您更好地了解何时使用其中一个或哪一个。
答案 2 :(得分:0)
每个结构定义实际上在.NET中创建了两种东西:堆对象(“盒装”)类型和存储位置(“未装箱”)类型。接口类型存储位置保存堆对象引用,因此将未装箱的结构存储到接口类型变量将要求将其内容复制到堆对象类型的实例。
受限于接口的泛型类型参数可以识别结构存储位置类型;然后,可以在没有装箱的情况下调用所讨论的存储位置上的接口方法。在某些情况下,这可以提供一些主要的性能优势。不幸的是,没有办法告诉编译器“我不想把这个东西装箱,如果我做任何需要装箱的东西,我宁愿让编译器发出尖叫声而不是默默插入一个拳击转换”。因此,在使用实现接口的结构时需要特别小心;如果一个人不愿意这样照顾,最好让所有结构都尝试:
表现得像对象(在这种情况下,它们应该很小,不允许任何突变方法而不是完全替换)或
只不过是用胶带粘在一起的变量组(即一堆公共字段)。
在一些特殊情况之外实现接口的东西,例如IEquatable<T>
,其唯一目的以结构为中心,通常应该是类。