What can generics do that you cannot do with the composition?

Given the class:

public class TestMain { } 

And two classes accepting instances of this class, one through generics:

 public class Test1<T> where T : TestMain { public Test1(T test) { } } 

And one without:

 public class Test2 { public Test2(TestMain test) { } } 

Why do you choose one of them?

+5
source share
3 answers

In this case, it is completely useless ... But let you have a method:

 // In Test1<T> public List<T> GetList() { } 

vs

 // In Test2 public List<TestMain> GetList() { } 

and let's say that you have

 public class TestSubclass: TestMain { } 

Now you can:

 List<TestSubclass> list1 = new Test1<TestSubclass>().GetList(); 

vs

 List<TestMain> list2 = new Test2().GetList(); 

See different return types? If this is useful or not, it depends on how you structure your program.

I will say that the more common case is to add a constraint of type new() generic type:

 public class Test1<T> where T : TestMain, new() 

Now in Test1 you could:

 public T GetNew() { return new T(); } 

This is a "trick" that Test2 cannot do, because it will always return a new TestMain()

+5
source

The difference is that the generic version takes the actual type for T , where the other only provides TestMain .

So say you added property:

 public class Test1<T> where T : TestMain { public T SomeProperty { get; private set; } public Test1(T test) { SomeProperty = test; } } public class Test2 { public TestMain SomeProperty { get; private set; } public Test2(TestMain test) { SomeProperty = test; } } 

And say that you are introducing a derived class:

 public class TestMain2 : TestMain { public string Foo2 { get; set; } } 

Then in Test2 you cannot access Foo2 from TestMain2.SomeProperty without casting, while in the T SomeProperty generic class the actual derived type with all its members will be displayed.

0
source

General illustration.

Class Declarations

 /// <summary> /// some base class /// </summary> public class BaseClass { public string Name { get; set; } public BaseClass() { this.Name = "I'm basic class"; } } /// <summary> /// inherited class 1 /// </summary> public class CoolClass : BaseClass { public string Name { get; set; } public CoolClass() { this.Name = "I'm cool class :)"; } } /// <summary> /// inherited class 2 /// </summary> public class SadClass : BaseClass { public string Name { get; set; } public SadClass() { this.Name = "I'm sad class :("; } } /// <summary> /// container /// </summary> /// <typeparam name="T"> element type </typeparam> public class UniversalContainer<T> where T : BaseClass { public List<T> Container { get; private set; } public UniversalContainer() { this.Container = new List<T>(); } } 

Using

 UniversalContainer<string> stringContainer = new UniversalContainer<string>(); // wrong UniversalContainer<BaseClass> baseContainer = new UniversalContainer<BaseClass>(); // right UniversalContainer<CoolClass> coolContainer = new UniversalContainer<CoolClass>(); // right UniversalContainer<SadClass> sadContainer = new UniversalContainer<SadClass>(); // right baseContainer.Container.Add(new BaseClass()); // right baseContainer.Container.Add(new SadClass()); // right baseContainer.Container.Add(new CoolClass()); // right coolContainer.Container.Add(new BaseClass()); // wrong coolContainer.Container.Add(new SadClass()); // wrong coolContainer.Container.Add(new CoolClass()); // right sadContainer.Container.Add(new BaseClass()); // wrong sadContainer.Container.Add(new SadClass()); // right sadContainer.Container.Add(new CoolClass()); // wrong 
0
source

All Articles