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