2

In the question “ C# generics: cast generic type to value type ”, both Eric Lippert and Jon Skeet says the following approach is not a good solution

//return new T { BusinessType = (U)(object)this }; //Eric Lippert answer (Not suggested)              
//return new T { BusinessType = (dynamic)this }; //Jon Skeet answer (Not suggested)

There was a code redundancy problem in my C# .Net 4.0 solution. The GetCalculator() method was repeated in both EngineDesignPatent and BenzolMedicinePatent.

    public override InvestmentReturnCalculator GetCalculator()
    {
        IntellectualRightsInvestmentReturnCalculator c = new IntellectualRightsInvestmentReturnCalculator();
        c.BusinessType = this;
        return c;
    }

Though not preferable, @Kit mentioned the following approach to avoid the redundancy in “ Refactoring Code to avoid Type Casting ”.

//BusinessBaseClass
public abstract class BusinessBaseClass<T, U> : EntityBaseClass, IBusiness
    where T : InvestmentReturnCalculator<U>, new()
    where U : IBusiness
{
    public virtual InvestmentReturnCalculator GetCalculator()
    {
        //return new T { BusinessType = (U)(object)this };  //Eric Lippert answer (Not suggested)
        return new T { BusinessType = (dynamic)this }; //Jon Skeet answer (Not suggested)
    }
}

QUESTION

What is the alternative to avoid code redundancy without the double cast approach?

CODE

Business Type Abstractions

public interface IBusiness
{
    InvestmentReturnCalculator GetCalculator();
}


public interface IRetailBusiness : IBusiness
{
    double GrossRevenue { get; set; }
}

public interface IIntellectualRights : IBusiness
{
    double Royalty { get; set; }
}

public abstract class EntityBaseClass
{

}

Calculator

public abstract class InvestmentReturnCalculator
{
    public abstract double ProfitElement { get;  }

    public double GetInvestmentProfit()
    {
        double profit = 0;
        if (ProfitElement < 5)
        {
            profit = ProfitElement * 5 / 100;
        }
        else
        {
            profit = ProfitElement * 10 / 100;
        }
        return profit;
    }
}

public abstract class InvestmentReturnCalculator<T> : InvestmentReturnCalculator where T : IBusiness
{
    public T BusinessType { get; set; }
}

public class RetailInvestmentReturnCalculator : InvestmentReturnCalculator<IRetailBusiness>
{
    public override double ProfitElement { get { return BusinessType.GrossRevenue; } }
}

public class IntellectualRightsInvestmentReturnCalculator : InvestmentReturnCalculator<IIntellectualRights>
{
    public override double ProfitElement { get { return BusinessType.Royalty; } }
}

Concrete Business Type Entites

public class EngineDesignPatent : BusinessBaseClass<IntellectualRightsInvestmentReturnCalculator, IIntellectualRights>, IIntellectualRights
{
    public double Royalty { get; set; }
    public EngineDesignPatent(double royalty)
    {
        Royalty = royalty;
    }

    //public override InvestmentReturnCalculator GetCalculator()
    //{
    //    IntellectualRightsInvestmentReturnCalculator c = new IntellectualRightsInvestmentReturnCalculator();
    //    c.BusinessType = this;
    //    return c;
    //}
}

public class BenzolMedicinePatent : BusinessBaseClass<IntellectualRightsInvestmentReturnCalculator, IIntellectualRights>, IIntellectualRights
{
    public double Royalty { get; set; }
    public BenzolMedicinePatent(double royalty)
    {
        Royalty = royalty;
    }

    //public override InvestmentReturnCalculator GetCalculator()
    //{
    //    IntellectualRightsInvestmentReturnCalculator c = new IntellectualRightsInvestmentReturnCalculator();
    //    c.BusinessType = this;
    //    return c;
    //}
}

public class BookShop : BusinessBaseClass<RetailInvestmentReturnCalculator, IRetailBusiness>, IRetailBusiness
{
    public double GrossRevenue { get; set; }
    public BookShop(double grossRevenue)
    {
        GrossRevenue = grossRevenue;
    }

    //public override InvestmentReturnCalculator GetCalculator()
    //{
    //    RetailInvestmentReturnCalculator c = new RetailInvestmentReturnCalculator();
    //    c.BusinessType = this;
    //    return c;
    //}
}

Client

    static void Main(string[] args)
    {

        #region MyBusines

        List<IBusiness> allMyProfitableBusiness = new List<IBusiness>();

        BookShop bookShop1 = new BookShop(75);
        EngineDesignPatent enginePatent = new EngineDesignPatent(1200);
        BenzolMedicinePatent medicinePatent = new BenzolMedicinePatent(1450);

        allMyProfitableBusiness.Add(bookShop1);
        allMyProfitableBusiness.Add(enginePatent);
        allMyProfitableBusiness.Add(medicinePatent);

        #endregion

        var investmentReturns = allMyProfitableBusiness.Select(bus => bus.GetCalculator()).ToList();

        double totalProfit = 0;
        foreach (var profitelement in investmentReturns)
        {
            totalProfit = totalProfit + profitelement.GetInvestmentProfit();
            Console.WriteLine("Profit: {0:c}", profitelement.GetInvestmentProfit());
        }

        Console.ReadKey();
    }

REFERENCES

  1. C# generics: cast generic type to value type
  2. Refactoring Code to avoid Type Casting
  3. Refactoring class design to convey the design intention
Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418

0 Answers0