Reputation: 1624
I am struggling to find a scenario where it would make sense to use a non-generic interface as a generic type constraint. Below is an arbitrary example where the non-generic method (RideCar2) is simpler than the generic method RideCar.
class Program
{
static void Main(string[] args)
{
var car = new Merc();
RideCar(car);
RideCar2(car);
}
static void RideCar<T>(T t) where T : ICar
{
t.StartEngine();
t.StopEngine();
}
static void RideCar2(ICar car)
{
car.StartEngine();
car.StopEngine();
}
}
public interface ICar
{
void StartEngine();
void StopEngine();
}
public class Merc : ICar
{
public void StartEngine() { Console.WriteLine("Merc start"); }
public void StopEngine() { Console.WriteLine("Merc stop"); }
}
It is obvious that RideCar2 is a much better implementation as it has less noise.
Is there a scenario where a non-generic interface used as a generic type constraint makes sense?
FURTHER EXAMPLES (As per the responses)
static T RideCar(T t) where T : ICar
{
t.StartEngine();
t.StopEngine();
return t;
}
Using a normal method still renders use of generic method useless, see below:
static ICar RideCar(ICar car)
{
car.StartEngine();
car.StopEngine();
return car;
}
static void RideCar(T t) where T : ICar, ICanTimeTravel
{
t.StartEngine(); // ICar
t.TravelToYear(1955); // ICanTimeTravel
t.StopEngine(); // ICar
}
Using a normal method with multiple paramaters still renders use of generic method useless, see below:
static void RideCar(ICar car, ICanTimeTravel canTimeTravel)
{
car.StartEngine();
canTimeTravel.TravelToYear(1955);
car.StopEngine();
}
Upvotes: 1
Views: 276
Reputation: 3212
Yes, there is. Consider:
static T RideCar<T>(T t) where T : ICar
{
t.StartEngine();
t.StopEngine();
return t;
}
This will return the specific type. Now you can use the implementation specifics without having to cast it back to the implementation type, which is bad practice.
Also, you can have multiple interface constraints on the same generic argument:
static void RideCar<T>(T t) where T : ICar, ICanTimeTravel
{
t.StartEngine(); // ICar
t.TravelToYear(1955); // ICanTimeTravel
t.StopEngine(); // ICar
}
Lastly, even though this is sometimes considered code smell, you can use the new()
constraint along with your interface constraint, in order to create instances of your implementation type inside the method:
static T Create<T>() where T : ICar, new()
{
T t = new T();
return t;
}
Upvotes: 5
Reputation: 7301
It depends. In your case the non-generic way is preferred.
If you want to call methods that are declared on different interfaces then the generic-declaration with type-constraints makes sense:
public void Test<T>(T value, T other)
where T: IEquatable<T>, IComparable<T>
{
value.Equals(other); //in IEquatable<T>
value.CompareTo(other); //in IComparable<T>
}
But in that case I prefer using a base class if possible and use it in the following method without any type-constraints:
public class BaseCar<T> : IEquatable<T>, IComparable<T>, ICar
{
/// [...]
}
public void Test<T>(BaseCar<T> car1, BaseCar<T> car2)
where T: IEquatable<T>, IComparable<T>
{
car1.Equals(car2);
car1.CompareTo(car2);
}
or without generics but limitation to ICar:
public class BaseCar : IEquatable<ICar>, IComparable<ICar>
{
/// [...]
}
public void Test(BaseCar car1, BaseCar car2)
{
car1.Equals(car2);
car2.CompareTo(car2);
}
Upvotes: 0