简体   繁体   English

如果我们使用的所有类通常都继承自某个公共类,那么为什么需要泛型?

[英]Why do we need generics if all classes we used usually inherit from some common class?

Good day. 美好的一天。 Generics usually used like this: 通常这样使用泛型:

class MyList<T>
{
    public T data;
    public MyList<T> nextElement;
}

Why not instead use follow: 为什么不改为使用Follow:

class MyList
{
    public object data;
    public MyList nextElement;
}

Or even: 甚至:

class MyStructure<T> where T : SomeCommonClass
{
    public T data;
    public MyStructure<T> nextElement;
    public MyStructure<T> prevElement;
}

and instead: 而是:

class MyStructure
{
    public SomeCommonClass data;
    public MyStructure nextElement;
    public MyStructure prevElement;
}

Update: 更新:

Well, I am afraid that you are not completely understood me correctly, and even downgraded my question. 好吧,恐怕您不能完全正确地理解我,甚至降级了我的问题。 Example without generics, that work correctly: 没有泛型的示例可以正常工作:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

        MyNode nodeButton = new MyNode("nodeButton", new Button());
        MyNode nodeTextBox = new MyNode("nodeTextBox", new TextBox());
        MyNode nodeCheckBox = new MyNode("nodeCheckBox", new CheckBox());
        MyList myList = new MyList() { nodeButton, nodeTextBox, nodeCheckBox };
        for (int i = 0; i < myList.Count;i++)
        {
            this.Controls.Add(myList[i].Data);
            myList[i].Data.Left = 100 * i;
        }
    }
}

public class MyNode
{
    public MyNode(string name, Control data)
    {
        Data = data;
        Name = name;
    }
    public string Name { get; private set; }
    public Control Data { get; private set; }
}

public class MyList : Collection<MyNode>
{
    protected override void InsertItem(int index, MyNode item)
    {
        base.InsertItem(index, item);
        item.Data.MouseClick += new MouseEventHandler((sender, e) => { MessageBox.Show(item.Name); });
    }
}

And same example with generics, that generates an error at compile time: 与泛型相同的示例在编译时生成错误:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

        MyNode<Button> nodeButton = new MyNode<Button>("nodeButton", new Button());
        MyNode<TextBox> nodeTextBox = new MyNode<TextBox>("nodeTextBox", new TextBox());
        MyNode<CheckBox> nodeCheckBox = new MyNode<CheckBox>("nodeCheckBox", new CheckBox());
        MyList myList = new MyList() { (MyNode<Control>)nodeButton, (MyNode<Control>)nodeTextBox, (MyNode<Control>)nodeCheckBox };
        for (int i = 0; i < myList.Count;i++)
        {
            this.Controls.Add(myList[i].Data);
            myList[i].Data.Left = 100 * i;
        }
    }
}

public class MyNode<T> where T : Control
{
    public MyNode(string name, T data)
    {
        Data = data;
        Name = name;
    }
    public string Name { get; private set; }
    public T Data { get; private set; }
}

public class MyList : Collection<MyNode<Control>>
{
    protected override void InsertItem(int index, MyNode<Control> item)
    {
        base.InsertItem(index, item);
        item.Data.MouseClick += new MouseEventHandler((sender, e) => { MessageBox.Show(item.Name); });
    }
}

According to you, the first version is bad practice, because type safety is broken, but the second version does not allow type casting! 根据您的说法,第一个版本是不好的做法,因为类型安全性已被破坏,但是第二个版本不允许类型转换!

In both cases, you can lose a lot of information about the object, and with it, a lot of type safety. 在这两种情况下,您都会丢失有关该对象的大量信息,并因此丢失大量类型安全性。 Casting is not pleasant. 铸造不愉快。 You also lose the ability to be sure that a list only contains objects of a certain type. 您还将失去确保列表包含某种类型的对象的能力。

There's also a significant performance loss when using value types; 使用值类型时,也会造成严重的性能损失。 they have to be boxed into and unboxed out of object , which is slow, and again, not safe. 他们已被装箱入和拆箱出object ,这是缓慢的,并再次,也不安全。

In fact, what you suggested did (well, still does) exist! 实际上,您所建议的确实存在(很好,仍然存在)! It was called ArrayList and was horrible. 它被称为ArrayList并且非常可怕。

From MSDN 从MSDN

Generics let you tailor a method, class, structure, or interface to the precise data type it acts upon. 泛型使您可以根据其作用的确切数据类型定制方法,类,结构或接口。

When you declare something as an object , you need to cast it to the appropriate datatype before performing the type-specific operations. 当您将某物声明为object ,需要在执行特定于类型的操作之前将其强制转换为适当的数据类型。 Likewise, in the case of the example with derived classes, if you use only the base class, you lose the ability to use properties of the derived classes, making it pointless. 同样,在具有派生类的示例中,如果仅使用基类,则会失去使用派生类的属性的能力,从而使其毫无意义。

Further in the documentation, an advantage is mentioned explicitly: 此外,在文档中,明确提到了一个优点:

When you create an instance of a generic class, you specify the actual types to substitute for the type parameters. 创建泛型类的实例时,可以指定实际类型来代替类型参数。 This establishes a new generic class, referred to as a constructed generic class, with your chosen types substituted everywhere that the type parameters appear. 这将建立一个新的泛型类,称为构造的泛型类,您选择的类型将在出现类型参数的所有位置替换。 The result is a type-safe class that is tailored to your choice of types. 结果是为您选择的类型量身定制的类型安全类。

This means that you get type safety in your code. 这意味着您可以在代码中获得类型安全性。 At the same time, you get highly reusable code since you only need to plug in the appropriate type. 同时,由于只需要插入适当的类型,您就可以获得高度可重用的代码。

Reference: http://msdn.microsoft.com/en-us/library/ms172192(v=vs.110).aspx 参考: http : //msdn.microsoft.com/zh-cn/library/ms172192(v=vs.110).aspx

Because you can do this with a generic list: 因为您可以使用通用列表来执行此操作:

int sum = 0;
List<int> list = GetList();
foreach(var item in list) // the compiler knows this is an int
{
    sum += item; // This would not be possible with an `object`
}

Notice how allowing the compiler to know what type my list is makes it possible for me to do things with the object in the list that would otherwise require a cast. 请注意,如何允许编译器知道列表的类型,这使我可以对列表中的对象进行处理,否则将需要强制转换。 Since I know at compile-time what type of object I'm dealing with, I can catch errors where I try to do something I'm not allowed to before ever running this code. 由于我在编译时知道我要处理的对象类型,因此在运行此代码之前,我会尝试执行不允许执行的操作时遇到错误。

Generics provides a lot of benefits like type safety and avoiding boxing and unboxing. 泛型提供了很多好处,例如类型安全和避免装箱和拆箱。 Generics is fast as compare to using objects because it avoids boxing and unboxing. 与使用对象相比,泛型速度更快,因为它避免了装箱和拆箱。 For getting more details on the benefits see this and if you are new the Generics visit following links: 为了得到关于好处的更多详情,请参阅 ,如果你是新的泛型访问以下链接:

An Introduction to C# Generics C#泛型简介

Generics (C# Programming Guide) 泛型(C#编程指南)

Update: 更新:

If you understand the correct meaning of type safety then it won't be difficult for you to understand that Generics purpose fully doesn't allow user to type cast the object. 如果您了解类型安全的正确含义,那么您将不难理解Generics目的完全不允许用户键入强制转换对象。 If you are so sure about the type casting then you can write your own Cast<>() method in the MyNode class which can cast type MyNode<T1> to MyNode<T2> . 如果您对类型转换非常确定,则可以在MyNode类中编写自己的Cast<>()方法,该方法可以将类型MyNode<T1>MyNode<T2> If you know the scenario and if you are so sure about the types and the castings and if you know the future changes won't conflict with the current, then don't use Generics . 如果您知道这种情况,并且对类型和类型有把握,并且知道将来的更改不会与当前版本冲突,那么不要使用Generics In programing we cannot use everything at every place, it all depends on the scenarios, and the practices which best fits the scenarios are used. 在编程时,我们不能在所有地方都使用所有内容,而这一切都取决于场景,并且使用了最适合场景的实践。 So you should use Generics wherever it fits best and you want to take advantages of it. 因此,您应该在最适合的地方使用Generics ,并且要利用它。 I hope you will understand what I am trying to explain. 希望您能理解我要解释的内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我们需要将Object类作为所有类的基类? - Why do we need to have Object class as baseclass for all the classes? 为什么我们需要密封类? - Why do we need sealed classes? 我们什么时候需要从我们继承的 class 实现的接口重新继承? - When do we need to re-inherit from an interface that has been implemented by a class from which we are inheriting? 要创建一个包含比其BASE更多的信息的类,是否需要从其继承或Compose? - To creat a class with additional information to carry than its BASE, do we need to Inherit from it or Compose? 为什么我们需要为类和属性装饰序列化属性或实现一些用于持久化数据的接口? - Why do we need to decorate serialisation attributes to classes and properties or implement some interface for persisting the data? 对于局部类的所有实例化,是否都需要关键字partial? - Do we need a keyword partial for all instantiation of partial classes? 为什么我们需要反思呢? - Why we need Reflection at all? 为什么我们需要创建类变量来获取和设置属性? - Why do we need to create class variables to get and set a property? 我们是否需要处理资源以及为什么在WCF中需要 - Do we need Disposing of resources and why do we need in WCF 为什么我们需要将类库项目继承的程序集的引用添加到使用者项目中? - Why do we need to add a reference to an assembly, from which a class library project inherits, into a consumer project?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM