danielp
danielp

Reputation: 291

ASP.NET MVC - Polymorphic domain classes and view models

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

Answers (1)

eulerfx
eulerfx

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

Related Questions