C#:System.Object vs Generics

我很难理解何时使用Object(装箱/拆箱)与何时使用generics。

例如:

public class Stack { int position; object[] data = new object[10]; public void Push (object o) { data[position++] = o; } public object Pop() { return data[--position]; } } 

VS.

 public class Stack { int position; T[] data = new T[100]; public void Push(T obj) {data[position++] = obj; } public T Pop() { return data[--position]; } } 

我应该使用哪一个以及在什么条件下? 看起来像System.Object方式,我可以拥有当前生活在我的堆栈中的各种类型的对象。 所以这不总是更可取吗? 谢谢!

总是使用generics! 使用对象的结果进行强制类型的强制转换操作和装箱/取消装箱。 由于这些原因,仿制药更快更优雅(无铸造)。 而且 – 主要原因 – 你不会使用generics获得InvalidCastException

因此,generics更快,并且在编译时可以看到错误。 System.Object意味着运行时exception和转换,这通常会导致较低的性能(有时甚至更低)。

几乎总是希望使用generics。

使用System.Object作为“常规类型”的应用程序:

  • 在旧的FX2之前的应用程序中,因为generics不可用。
  • 当您需要混合不同的类型时,如ASP.NET会话和应用程序对象。

请注意,在您的第一个示例(非generics)中,用法如下所示:

 Stack s = ...; s.Push("Hello"); s.Push(1.23); double d = (double) s.Pop(); string t = (string) s.Pop(); 

你真的想避免所有这些类型转换(为了可读性,安全性和性能)。

很多人都建议使用generics,但看起来他们都错过了这一点。 它通常不是关于拳击原始类型或转换的性能命中,而是关于让编译器为你工作。

如果我有一个字符串列表,我希望编译器向我certificate它将始终包含一个字符串列表。 generics就是这样 – 我指定了意图,编译器为我certificate了这一点。

理想情况下,我更喜欢一个更丰富的类型系统,你可以说,例如一个类型(即使它是一个引用类型)不能包含空值,但遗憾的是C#目前没有提供。

虽然有时您会想要使用非generics集合(例如,想想缓存),但您几乎总是拥有同质对象的集合而不是异构对象。 对于同质集合,即使它是基本类型或接口变体的集合,使用generics总是更好。 这将使您无需在使用之前将结果转换为真实类型。 使用generics使您的代码更有效和可读,因为您可以省略代码来执行强制转换。

如果可能的话,generics总是首选。

除了性能之外,generics还允许您保证您正在使用的对象类型。

这是首选的主要原因是编译器知道对象是什么类型,因此它可以为您提供立即找到的编译错误,而不是可能仅在您未测试的某些情况下发生的运行时错误。

对于object类型,正如您所说,您需要执行装箱和拆箱,这会很快变得乏味。 使用generics,没有必要。

此外,我更倾向于更具体地说一个类可以使用什么类型的对象,而generics为此提供了很好的基础。 为什么首先要混合不相关的数据类型? 您的特定堆栈示例强调了generics优于基本object数据类型的优势。

 // This stack should only contain integers and not strings or floats or bools Stack intStack = new Stack(); intStack.Push(1); 

请记住,使用generics,您可以指定接口,以便您的类可以与许多不同类的对象进行交互,前提是它们都实现了相同的接口。

当您希望结构处理单一类型时,请使用generics。 例如,如果您想要一个字符串集合,您可能希望实例化强类型字符串列表,如下所示:

 List myStrings = new List(); 

如果你想让它处理多种类型,你可以不用generics,但是你会对装箱/拆箱操作造成很小的性能损失。

这一切都取决于你长期需要什么。

与大多数答案不同,我不会说“总是使用仿制药”,因为有时你需要将猫与黄瓜混合。

无论如何,尝试坚持使用generics,因为在其他答案中已经给出了所有原因,例如,如果你需要组合猫和狗创建基类Mammal并且拥有Stack

但是当你真的需要支持所有可能的类型时,不要害怕使用对象,除非你误解它们,否则它们不会咬人。 🙂