Reputation: 291
Let's consider a domain abstract class for an order history and concrete classes considering events such like payments, cancellations, reactivations etc (the following code is a VERY simplified version)
public abstract class OrderEvent
{
protected OrderEvent(DateTime eventDate)
{
EventDate = eventDate;
}
public abstract string Description { get; }
public DateTime EventDate { get; protected set; }
}
public class CancellationEvent : OrderEvent
{
public CancellationEvent(DateTime cancelDate)
: base(cancelDate)
{
}
public override string Description { get { return "Cancellation"; } }
}
public class PaymentEvent : OrderEvent
{
public PaymentEvent(DateTime eventDate, decimal amount, PaymentOption paymentOption) : base(eventDate)
{
Description = description;
Amount = amount;
PaymentOption = paymentOption;
}
public override string Description { get{ return "Payment"; } }
public decimal Amount { get; protected set; }
public PaymentOption PaymentOption { get; protected set; }
}
Now I have to build a ViewModel for my ASP.NET MVC project upon this domain model that will encapsulate all the events into a single class for a grid exhibition on the view.
public class OrderHistoryViewModel
{
public OrderHistoryViewModel(OrderEvent orderEvent)
{
// Here's my doubt
}
public string Date { get; protected set; }
public string Description { get; protected set; }
public string Amount { get; protected set; }
}
How can I access the specific properties from concrete classes, like the Amount property on PaymentEvent without doing some smelly thing like switch or if?
Thanks!
Upvotes: 2
Views: 444
Reputation: 37709
On way is to do double dispatch granted that you're on .NET 4 and above:
public class OrderHistoryViewModel
{
public OrderHistoryViewModel(OrderEvent orderEvent)
{
// this will resolve to appropriate method dynamically
(this as dynamic).PopulateFrom((dynamic)orderEvent);
}
void PopulateFrom(CancellationEvent e)
{
}
void PopulateFrom(PaymentEvent e)
{
}
public string Date { get; protected set; }
public string Description { get; protected set; }
public string Amount { get; protected set; }
}
Personally, I don't really mind doing if/switch statements in this type of code. This is application boundary code that doesn't need to be very pretty and having it be explicit can be helpful. What C# really needs are algebraic types such as the union type in F#. This way, the compiler will ensure that you handle all cases (sub-types) explicitly.
Upvotes: 2