When I was learning C# generics, some articles mentioned using generics is type-safe during execution by preventing the usage of data whose type is different from the one used in the declaration. Link I dont get why this should be an issue, if type is wrong shouldn't it crashed when build?
I'm curious about when and how this kind of problem could happen.
CodePudding user response:
I'm curious about when and how this kind of problem could happen.
Basically, when using types that don't support generics but could. The classic example is probably ArrayList
- the pre-generics equivalent of List<T>
. ArrayList.Add
just accepts object
, so you can add anything into it - but typically code assumes just a specific type. So for example:
var people = new ArrayList();
people.Add(new Person("Jon"));
// ... later in the code
foreach (string name in people)
{
Console.WriteLine(name);
}
That crashes with a ClassCastException
, because the list contains a Person
reference, which is then implicitly cast to a string
reference. That wouldn't happen with generics, where you'd have either a List<Person>
or a List<string>
, and spot errors at compile-time.
CodePudding user response:
Generics are indeed type safe in compile time. I'd say that article in the sentence:
Client code that uses generics is type-safe during execution by preventing the usage of data whose type is different from the one used in the declaration
is referring to the implicit benefit of eliminating runtime invalid cast exceptions.
CodePudding user response:
Generics provide type safety during compile-time, meaning you can't compile your code if the generic constraint is violated. And that is almost always preferable over a runtime exception.
void DoSomething<T>(T foo) where T : FooBase { }
If I try now to write code like this:
var myBar = new Bar(); // Does not inherit from FooBase
DoSomething(myBar);
Then I get this:
error CS0311: The type 'Bar' cannot be used as type parameter 'T' in the generic type or method 'DoSomething(T)'. There is no implicit reference conversion from 'Bar' to 'FooBase'.
And this happens during compile time. Perfect.
You might have also seen generics without any constraint:
void DomSomething<T>(T foo);
This will go a bit away from your original question, but one could ask what is the benefit over let's say: DoSomething(object obj)
. And here we have a difference between value types and reference types - namely boxing and unboxing happens when using the version with object
.
So generics can also have some performance benefits, next to the type safety and reusability aspect.
CodePudding user response:
One of the major benefits of generics in not just type-safety as is, but allowing writing generalized code while still maintaining type-safety and without degrading performance for value-types. For example we can generalize over collection of interface:
public interface IHaveId { int Id {get;}}
public T GetOrAddById<T>(IList<T> col, int id, T val) where T : class, IHaveId
{
var item = col.FirstOrDefault(x => x.Id == id);
if (item == null)
{
item = val;
col.Add(item);
}
return item;
}
Now you can't pass anything that does not implement the concrete interface.
Before the generics the only way of having generalized collection would be something like ArrayList
(which can be compared to List<object>
), so user could put anything in it without any type-safety.