What is the advantage of using C # Generics restrictions

Can someone tell me what is the difference between the following

public class CarCollection<T>:List<T> where T:Car{} 

and

 public class CarCollection:List<Car>{} 

It seems to me that they are doing the same thing, create a type-safe collection of Car objects.

+4
source share
7 answers

The upper part creates a typed collection of cars or everything that comes from a car such as SportsCar.

 public class SportsCar : Car { bool Turbo { get; set;} } 

Upstairs I could create a collection of sports cars

 var sports = new CarCollection<SportsCar>(); sports.Add(new SportsCar()); ... sports.First().Turbo = true; 

Below I will have

 var cars = new CarCollection<Car>(); cars.Add(new SportsCar()); ((SportsCar)cars.First()).Turbo = true; 

It looks like a collection of objects and a collection of strings. :)

0
source

Limitations are good when you need information about the generic type argument. By restricting a type, you not only limit the set of valid type arguments, but also allow yourself to make decisions at compile time based on the common elements of this type set.

In your specific example, a general restriction does not give any benefit, but in other circumstances they may. Consider this example:

 T foo<T>() { return null; } 

This method cannot compile because the compiler knows (as it should when I wrote the method) that the generic type argument can be a value type that cannot be set to null . By adding a constraint, I can compile this code:

 T foo<T>() where T : class { return null; } 

Now I have limited a valid set of arguments of a general type to classes only. Since the compiler now knows that T must be a class, it allows me to return null , since there are no scripts in which null cannot be returned. Although this is not a very useful example, I am sure that you can extrapolate in ways that can be useful.

+7
source

If you implement a generic type that will perform comparisons, a where clause is needed. For instance:

 public class Foo<T> where T : IComparable<T> { public static void Bar(T blah, T bloo) { if(blah.CompareTo(bloo) < 0) //needs the constraint Console.WriteLine("blee!"); } } 

This is a concrete example, but it illustrates a concept in which your where clause indicates that your generic type will adhere to the type and, therefore, be able to use the functionality.

+4
source

I think the second format is misleading: β€œCar” is a template parameter, not a reference to the β€œCar” class that you supposedly defined.

The first format allows you to call the members (methods and properties) of the Car class in instances of T in the template class.

 class Car { public void drive() {} } public class CarCollection<T>:List<T> where T:Car { List<T> list; void driveCars() { foreach (T car in list) { //know that T is Car car.drive(); } } } public class CarCollection<Car>:List<Car> { List<Car> list; void driveCars() { foreach (Car car in list) { //compiler error: no relation between the 'Car' template parameter //and the 'Car' class car.drive(); } } } 
+1
source

All about showing intentions. If the user of your class knows what restrictions are placed in the type parameter, they can create their own code with higher precision.

In addition, your code becomes more self-documenting.

0
source

The first example is much more flexible. You can use it with a list of any object if T is Car

The second example says that it should be a car. You could not use the second with CompactCar or Truck . That is, if CompactCar or Truck sourced from Car

0
source

After going through all the posts, I think that one of the most valuable uses was not discussed (unless I missed it).

You can specify that T must implement more than one interface. Say you want it to be ISomething , ISomethingElse and IOneOtherThing . You can specify these three specific interfaces.

 static void DoSomething<T>(T myobj) where T : ISomething, ISomethingElse, IOneOtherThing { myobj.Something(); myobj.SomethingElse(); myobj.OneOtherThing(); } 

The case may be when you need to be able to compare (IComparable) two generic types and return a clone (IClonable) of one. Or something like that.

I am trying to think of a clean and reusable way to do the same without this function.

0
source

Source: https://habr.com/ru/post/1310572/


All Articles