考虑以下情况:
int Caller1<T>(T t) where T : IInterface {...}
T Caller2<T>() where T : IInterface {...}
class Wrappee // doesn't implement IInterface, but could
??? Wrapper : IInterface {
private readonly Wrappee _wrappee;
// methods call _wrappee's methods
}
现在,在struct
和class
之间进行选择的一般建议是“如果您需要值语义而使用struct
,并且class
用于参考语义”。我们需要的语义是“引用Wrappee
”。但似乎我们仍然可以使Wrapper
成为一个结构:复制它的值与复制Wrappee
引用相同,并且副本将引用相同的对象!开销较低,scalar replacement可能能够将局部变量减少到零。似乎可以在_wrappee
上调用甚至是变异方法。
我错过了什么吗?是否有充分理由让Wrapper
成为一个班级?
如果来电者不通用,则有一个:
int Caller(IInterface t) {...}
在这种情况下,Wrapper
应该是一个避免装箱的类。
对那些了解Haskell的人说:我正在尝试找到与newtype
最接近的.NET类似物。
更新:在第一种情况下,请参阅Professional .NET 2.0 Generics和Peter Ritchie on MSDN forums是否缺席拳击。
答案 0 :(得分:4)
是的,因为您将通过IInterface变量访问包装器,以避免装箱,它应该是一个类。
编辑:如果您通过类型为Wrapper的变量访问包装器,并访问Wrapper方法,而不是IInterface方法,那么结构就可以了。
答案 1 :(得分:2)
通常你的类/结构将通过你调用的方法在内部存储或传递(你没有显示Caller1和Caller2做的事情),在这种情况下它可能会被装箱。可能比你预期的更频繁。因此,除非你能证明结构更有效:不要打扰并坚持使用类。
此外,结构通常不赞成,除非它们代表类似数据类型的东西,所以选择一个类可能会阻止将来讨论不同的性质。
但是,如果性能确实是一个问题,并且如果您可以保证实例仅作为具有泛型类型约束的参数传递,并且从不存储在接口类型的字段或集合中,则.NET运行时当前内联结构将更有效,因为您的包装器结构将大部分被优化掉。但那是很多ifs。
答案 2 :(得分:0)
我会说课,因为你是封装行为,而不仅仅是数据。