0

Good day. Generics usually used like this:

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

Why not instead use 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!

Feofilakt
  • 1,341
  • 2
  • 13
  • 33
  • what is the question? – brainless coder Jun 26 '14 at 04:00
  • 1
    It sounds like your underlying question is: why would you use a type system that provides guarantees about types at compile time? And for the answer to that question, see [What to know before debating type systems](http://web.archive.org/web/20080822101209/http://www.pphsg.org/cdsmith/types.html). – Daniel Pryden Jun 26 '14 at 04:09

4 Answers4

9

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.

In fact, what you suggested did (well, still does) exist! It was called ArrayList and was horrible.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 1
    @Feofilakt: Your update uses generics inappropriately; that’s all. If a `Control` is what a `MyNode` should contain, make it able to contain that. If a `MyNode` should be generic across various types of controls, use generics. (You can also fix casting with operator overloading if you need it. Look up covariance.) – Ry- Jun 27 '14 at 04:35
  • MyNode should contain Control or any class, derived from Control. If MyNode not be generic across various types of controls, I will use, for example, "if (MyNode1.Data is Button)" or "if (MyNode1.Data is TextBox)". So, first case is not bad practic? – Feofilakt Jun 27 '14 at 04:54
  • @Feofilakt: The first case isn’t bad practice if you want it to contain controls. Runtime type identification, on the other hand, isn’t usually a good thing. – Ry- Jun 27 '14 at 16:19
3

From 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. 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

shree.pat18
  • 21,449
  • 3
  • 43
  • 63
2

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.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
2

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

Generics (C# Programming Guide)

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. 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>. 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. 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. I hope you will understand what I am trying to explain.

Community
  • 1
  • 1
Nitin Joshi
  • 1,638
  • 1
  • 14
  • 17
  • I get it. Everyone here told me that type safety - it is something good. In fact, type safety - it's just a concept that is useful in some cases. As well as generics. Right? – Feofilakt Jun 27 '14 at 05:30