添加结构:列表的接口<Interface>
Adding Struct : Interface to a List<Interface>
我需要在列表中将结构作为值类型传递。
假设我有一个派生自接口的结构:
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>
并且只添加这些结构是否安全,或者在 class 上做 MemberwiseClone 会更好吗?
我也在寻找效率,因为这将用于瓦片地图中的碰撞检测。
结构将被装箱。他们为什么不呢? List<IFoo>
中的每个值都必须是 IFoo
,因此您添加的每个结构实例都会通过装箱进行转换。
结构仍然是装箱的,因为 object
也是引用类型。在您的场景中,除非您将列表声明为特定值类型(List<Foo1>
或 List<Foo2>
),否则根本无法避免装箱。
一般来说,为"efficiency"使用结构体根本不是一件简单或显而易见的事情。特别是,简单地在 struct
中加入 class
并不能保证让你的代码执行得更好。首先以明显的方式编写代码(这里明显的意思是:使用 类),然后确定(通过分析)是否需要优化它,如果需要,如何优化。
如果您有一个列表,其中 I 是一个接口,并且您添加类型为 F1 和 F2[ 的元素=28=] 两者都实现了 I 接口,然后当您从列表中检索两个元素中的任何一个时,您可以使用关键字 **is ** 和继续对您从列表中获得的元素应用正确的转换。
例如:
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 中的元素被转换回原始值类型时,它应该被取消装箱。但是太多的拆箱和装箱会影响性能,并且由于您想执行碰撞检测之类的操作,这可能会降低性能。
您是否必须使用结构?由于对变量进行的装箱更改,如果您对存储的装箱对象执行操作,则可能无法正常运行,正如我提到的那样,过多的装箱可能会给您带来糟糕的结果。
在我看来,使用 MemberwiseClone 的 class 会更好。
您可以阅读 MSDN 上的 this 文章,其中详细介绍了结构和 classes 的优缺点,这可能有助于您更好地理解何时使用其中一个或另一个。
每个结构定义实际上在 .NET 中创建了两种东西:堆对象 ("boxed") 类型和存储位置 ("unboxed") 类型。接口类型存储位置包含堆对象引用,因此将未装箱的结构存储到接口类型变量将需要将其内容复制到堆对象类型的实例。
限制在接口上的泛型类型参数可以识别结构存储位置类型;然后可以在没有装箱的情况下调用相关存储位置上的接口方法。在某些情况下,这可以提供一些主要的性能优势。不幸的是,没有办法告诉编译器 "I don't want this thing boxed, and if I do anything which would require boxing I would rather have the compiler squawk than silently insert a boxing conversion"。因此,在使用实现接口的结构时需要格外小心;如果一个人不愿意如此小心,最好让所有结构都尝试:
表现得像对象(在这种情况下它们应该很小并且不允许除了完全替换之外的任何突变方法)或
只不过是用胶带粘在一起的变量组(即一堆public字段)。
实现接口的东西,除了像 IEquatable<T>
这样的唯一 目的 以结构为中心的少数特殊情况外,通常应该是 类。
我需要在列表中将结构作为值类型传递。 假设我有一个派生自接口的结构:
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>
并且只添加这些结构是否安全,或者在 class 上做 MemberwiseClone 会更好吗?
我也在寻找效率,因为这将用于瓦片地图中的碰撞检测。
结构将被装箱。他们为什么不呢?
List<IFoo>
中的每个值都必须是IFoo
,因此您添加的每个结构实例都会通过装箱进行转换。结构仍然是装箱的,因为
object
也是引用类型。在您的场景中,除非您将列表声明为特定值类型(List<Foo1>
或List<Foo2>
),否则根本无法避免装箱。
一般来说,为"efficiency"使用结构体根本不是一件简单或显而易见的事情。特别是,简单地在 struct
中加入 class
并不能保证让你的代码执行得更好。首先以明显的方式编写代码(这里明显的意思是:使用 类),然后确定(通过分析)是否需要优化它,如果需要,如何优化。
如果您有一个列表,其中 I 是一个接口,并且您添加类型为 F1 和 F2[ 的元素=28=] 两者都实现了 I 接口,然后当您从列表中检索两个元素中的任何一个时,您可以使用关键字 **is ** 和继续对您从列表中获得的元素应用正确的转换。
例如:
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 中的元素被转换回原始值类型时,它应该被取消装箱。但是太多的拆箱和装箱会影响性能,并且由于您想执行碰撞检测之类的操作,这可能会降低性能。
您是否必须使用结构?由于对变量进行的装箱更改,如果您对存储的装箱对象执行操作,则可能无法正常运行,正如我提到的那样,过多的装箱可能会给您带来糟糕的结果。
在我看来,使用 MemberwiseClone 的 class 会更好。
您可以阅读 MSDN 上的 this 文章,其中详细介绍了结构和 classes 的优缺点,这可能有助于您更好地理解何时使用其中一个或另一个。
每个结构定义实际上在 .NET 中创建了两种东西:堆对象 ("boxed") 类型和存储位置 ("unboxed") 类型。接口类型存储位置包含堆对象引用,因此将未装箱的结构存储到接口类型变量将需要将其内容复制到堆对象类型的实例。
限制在接口上的泛型类型参数可以识别结构存储位置类型;然后可以在没有装箱的情况下调用相关存储位置上的接口方法。在某些情况下,这可以提供一些主要的性能优势。不幸的是,没有办法告诉编译器 "I don't want this thing boxed, and if I do anything which would require boxing I would rather have the compiler squawk than silently insert a boxing conversion"。因此,在使用实现接口的结构时需要格外小心;如果一个人不愿意如此小心,最好让所有结构都尝试:
表现得像对象(在这种情况下它们应该很小并且不允许除了完全替换之外的任何突变方法)或
只不过是用胶带粘在一起的变量组(即一堆public字段)。
实现接口的东西,除了像 IEquatable<T>
这样的唯一 目的 以结构为中心的少数特殊情况外,通常应该是 类。