I am having some issues surrounding the calling of a generic method. In the example below, when I call ServiceCar
from the base class I get an error when that method is defined in Dealer as:
Definition 1: ServiceCar<C>(C carToService) where C: Car<C>
.
But I do not get an error in the base Class when that method is defined in Dealer as:
Definition 2: ServiceCar<C>(Car<C> carToService) where C: Car<C>
public abstract class Car<T> where T: Car<T>
{
public bool isServiced;
public string serviceMessage;
public virtual void SendToService()
{
Dealer.ServiceCar<T>(this); // error here when Definition 1 used
serviceMessage = "Your car is clean.";
}
}
public class Ford: Car<Ford>
{
public override void SendToService()
{
Dealer.ServiceCar<Ford>(this);
serviceMessage = "Your Ford is clean.";
}
}
public class Dealer
{
// When the parameter is defined as C (as commented below) an error occurs
// When the parameter is defined as Car<C> there are no errors
// public static void ServiceCar<C>(C carToService) where C : Car<C>
public static void ServiceCar<C>(Car<C> carToService) where C : Car<C>
{
carToService.isServiced = true;
}
}
My confusion is that Microsoft says that "where T: means the type argument must be or derive from the specified base class" Well in the case of definition 1 (which does not compile) C is Car<C>
. So why isn't the type constraint parameter helping me out. The error I am getting reads "...cannot convert from Car<T>
to T" What am I missing?
I think you a confusing different type parameters. Class Car<T>
has parameter T
and method ServiceCar<C>
has another type parameter C
. So you need to specify both type parameters in the method and class declaration:
ServiceCar<C, T>(C carToService) where C : Car<T>
Off hand it looks like your confusing generics and inheritance. Keep in mind what other developers might have to do when they inherit your code. I always opt for simplicity when possible.
public abstract class Car
{
public bool isServiced;
public string serviceMessage;
public abstract string TypeName { get; }
public virtual void SendToService()
{
Dealer.ServiceCar(this); // error here when Definition 1 used
servicesMessage = string.Format("Your {0} is clean.", Car.TypeName);
}
}
public class Ford: Car
{
public override string TypeName { get { return "Ford"; } }
//No need to override this because Ford inherits from Car
//public override void SendToService()
//{
// Dealer.ServiceCar<Ford>(this);
// serviceMessage = "Your Ford is clean.";
//}
}
public class Dealer
{
public static void ServiceCar(Car carToService)
{
carToService.isServiced = true;
}
}
When attempting to call
public static void ServiceCar<C>(C carToService) where C : Car<C>
with this
Dealer.ServiceCar<T>(this);
you are passing an expression of type Car<T>
to a method that wants an expression of type T
. The reason it wants an expression of type T
is because Dealer.ServiceCar<T>
is explicitly defining the C
as T
, so the carToService
parameter must be a T
.
However, Car<T>
is not convertable to T
. Why should it be? It does not inherit from T
. The only thing it inherits from is object
. Therefore, the compiler cannot convert an expression of type Car<T>
to an expression of type T
, just as indicated.
To be clear, the documentation that you site and your class definition states that T
must inherit from Car<T>
, but it does not say the inverse, that Car<T>
must inherit from T
.
In definition 1, Dealer.ServiceCar<T>
takes a parameter of type T
. You are passing this
into the method, which is of type Car<T>
. How are you going to convert Car<T>
to T
? The where
constraint only says T
is a Car<T>
, but not the other way around.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.