Reputation: 1120
Sorry if title of question is a little bit vague.
Suppose we have the following code
class ReportManager<T> where T : IPrint
{
public void MakePaperCopy(T t)
{
//...
t.Print();
//...
}
}
public interface IPrint
{
void Print();
}
It can be easily remade to non-generic version. Like this
class ReportManager
{
public void MakePaperCopy(IPrint print)
{
//...
print.Print();
//...
}
}
Are there some advantages in first case ? it seems no.
Can i say that every generic class with single where T: ISomeInterface
can be easily remade to non-generic version and it should be done because it reduces the complexity of code ?
Upvotes: 1
Views: 84
Reputation: 64943
In the first place, generics avoid a lot of casts. This can ends up in significant performance gains in intensive applications and services.
Secondly, it's not the same defining that a generic type parameter accepts any implementation of IPrint
(non-generic) than that the whole type will handle objects which are forced to implement IPrint
(generic).
Try to work on the following type requirement without generics:
T
to be IPrint
and inherit PrintablePaper
.Without generics, sadly, this would be implemented using reflection:
// Ugly as hell. And error prone, because it's verified during
// run-time...
if(typeof(IPrint).IsAssignableFrom(typeof(T)) && typeof(T).IsSubclassOf(typeof(PrintablePaper))
{
}
With generics: T : PrintablePaper, IPrint
and try to give a wrong type as generic argument, and compiler will say: slap in your face, slap in your face, ....
Basically, in terms of high-level programming, generics were introduced to enforce strongly-typing in C# even more. Generic constraints provide details to what would be an acceptable generic argument during compile-time. That is, generics are a good way to close a software architecture/design to grow based on specs defined by generic constraints.
About the whole repository sample, if your report manager will never need to handle specializations of IPrint
, generics are useless in that particular case: accepting implementations of IPrint
or a type which mandatorily will implement IPrint
is almost the same in your case.
In your case, it would be useful if you would need to inherit that class:
class ReportManager<T> where T : IPrint
{
public void MakePaperCopy(T t)
{
//...
t.Print();
//...
}
}
class SpecializedReportManager : ReportManager<FancyReport>
{
// Beat this without generics!!
// In inherited classes, you can work with the IReport
// implementation directly and without casts!
public void MakePaperCopy(FancyReport t)
{
//...
t.Print();
//...
}
}
Upvotes: 4
Reputation: 1561
It's not useless in all cases.
If you want to return this T
, then you may want to know the exact type.
Because when you are returning it, you can access to all the (accessible) members from the derived class, not only those from the base class/interface.
Upvotes: 5
Reputation: 5402
After commenting on romain-aga's post - there's yet another reason, on top of what everyone else said. If you have a constraint referencing a generic interface (say where T : IComparable<T>
) you simply won't be able to remake it into a non-generic version.
Upvotes: 0
Reputation: 8904
The generic form will prevent boxing in case of value types.
Also, you can have T implement multiple interfaces:
class ReportManager<T> where T : IPrint, IConvertible, IAnotherInterface
The 2nd form will obviously not work in that case.
Upvotes: 2