简体   繁体   中英

Abstract extension method inheritance from abstract class

I'm trying to achieve the following, not sure yet that it is at all possible: (Behind the scene is a CarFactory I tried to do - implementing the Factory design pattern)

I have a abstract class "Car" with solid properties that are shared between all cars and I have features like "RadioDisc", "FuelInjection" which not all cars have.

There could be several types of "RadioDisc" or "FuelInjection".

Each of these features follows a certain pattern, has shared properties but the installation process on a car is different.

I want each feature to make changes to Car based on a method that can do some stuff.

The extension should look something like this:

Car myCar = new Car();  //Car is a class which has solid props & List of Feature class
FuelInjection V1 = new FuelInjection(); 
myCar.Install<FuelInjection>(V1) ; 

Ideally it should do like this, but I have compiler error-

Extension method must be defined in a non-generic static class

Of course I don't want a general static method, I want a method that will have same signature but will do something diffrent to the car on each class that inherit Feature.

Example for feature is FuelInjection that add Cost to the car, and let's say improve FuelConsumption property on Car.

Abstract Feature class:

public abstract class Feature
{
    internal float _cost;

    public float Cost
    {
        get
        {
            return _cost;
        }
    }

    public abstract void Install<T>(this Car car) where T : Feature;
}

Specific feature:

  public class FuelInjection : Feature
    {
        public new void Install<T>(this Car car) where T : Feature
        {
            //In iDo some stuff to Car:
            car.price += this._cost; //this suppose to be the Feature instance. 
                                     //I want to add the cost to property "Price" in Car.
        }
}

Is that even possible in c#? Is there a different direction to go maybe?

You can always define an interface(or use your abstract class):

public interface IFeature
{
    void Install(Car car);
}

inherit from it:

public class Feature : IFeature, IComparable
{
    public void Install(Car car) 
    {
         ....
    }
}

and then make an extension:

public static class CarExt
{
     public static void InstallFeature(this Car car, IFeature feature) 
     {
         feature.Install(car);  
     }
}

in case of your abstract class it would be just:

public static class CarExt
{
     public static void InstallFeature(this Car car, Feature feature) 
     {
         feature.Install(car);  
     }
}

If I understood your problem correctly, you should be looking for decorator pattern.

Ref: http://www.dotnet-tricks.com/Tutorial/designpatterns/VRQT130713-Decorator-Design-Pattern---C

From the site:

"Decorator pattern is used to add new functionality to an existing object without changing its structure. Hence Decorator pattern provides an alternative way to inheritance for modifying the behavior of an object."

Code sample from dotnet-tricks site:

/// <summary>
/// The 'Component' interface
/// </summary>
public interface Vehicle
{
 string Make { get; }
 string Model { get; }
 double Price { get; }
}

/// <summary>
/// The 'ConcreteComponent' class
/// </summary>
public class HondaCity : Vehicle
{
 public string Make
 {
 get { return "HondaCity"; }
 }

 public string Model
 {
 get { return "CNG"; }
 }

 public double Price
 {
 get { return 1000000; }
 }
}

/// <summary>
/// The 'Decorator' abstract class
/// </summary>
public abstract class VehicleDecorator : Vehicle
{
 private Vehicle _vehicle;

 public VehicleDecorator(Vehicle vehicle)
 {
 _vehicle = vehicle;
 }

 public string Make
 {
 get { return _vehicle.Make; }
 }

 public string Model
 {
 get { return _vehicle.Model; }
 }

 public double Price
 {
 get { return _vehicle.Price; }
 }

}

/// <summary>
/// The 'ConcreteDecorator' class
/// </summary>
public class SpecialOffer : VehicleDecorator
{
 public SpecialOffer(Vehicle vehicle) : base(vehicle) { }

 public int DiscountPercentage { get; set; }
 public string Offer { get; set; }

 public double Price
 {
 get
 {
 double price = base.Price;
 int percentage = 100 - DiscountPercentage;
 return Math.Round((price * percentage) / 100, 2);
 }
 }

}

/// <summary>
/// Decorator Pattern Demo
/// </summary>
class Program
{
 static void Main(string[] args)
 {
 // Basic vehicle
 HondaCity car = new HondaCity();

 Console.WriteLine("Honda City base price are : {0}", car.Price);

 // Special offer
 SpecialOffer offer = new SpecialOffer(car);
 offer.DiscountPercentage = 25;
 offer.Offer = "25 % discount";

 Console.WriteLine("{1} @ Diwali Special Offer and price are : {0} ", offer.Price, offer.Offer);

 Console.ReadKey();

 }
}

The compiler message already told you that it's not possible in the way you are trying to do it. An extension method must be a static method of a static class.

So you can only declare your method as simple abstract/instance methods:

public abstract class Feature : IComparable
{
    internal float _cost;
    public abstract void Install(Car car);
}

public class FuelInjection : Feature
{
    public override void Install(Car car)
    {
        car.price += this._cost;
    }
}

But you can create a simple extension with a Feature parameter to almost wrap the call like you wanted:

public static class CarExtensions
{
    public static void Install(this Car car, Feature feature)
    {
        feature.Install(car);
    }
}

And us it like

myCar.Install(V1);

(assuming that V1 is your instance of FuelInjection ). There is no need for generics here as all features inherit from Feature .

But really, I don't see how this is better than calling V1.Install(car) directly.

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