简体   繁体   中英

Generic Type Constraint does not seem to be constraining anything

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM