lonelydev101
lonelydev101

Reputation: 1901

How to make generic object to accept two different class models

I want to have 2 very similar classes that will have some common behavior, but different properties, so I need to make these two classes Invoice and CreditNote to be under "one generic object" in this case called model

I was thinking to implement a inteface which will be having input object type like:

public interface IInvoice<T>
{
    T InvoiceType { get; set; }
}

But Im not quite sure if this is the way for this. Ultimately, I would like instancing these classes from interface: IInvoice = new Invoice();

Here is an example:


//380-invoice
if(Convert.ToInt32(invoiceType) == InvoiceTypeCodeEnumDto.Invoice.Id)
{
    Invoice model = new Invoice();
    model.RequestId = request.CorrelationId;
    model.SendToCir = "Auto";
}

//383-creditNote
if (Convert.ToInt32(invoiceType) == InvoiceTypeCodeEnumDto.CreditNote.Id)
{
    CreditNote model = JsonConvert.DeserializeObject<CreditNote>(request.Content)!;
    model.RequestId = request.CorrelationId;
    model.SendToCir = "Auto";
}

model.Name = "foo"; // not accesible

Upvotes: 0

Views: 204

Answers (1)

AceGambit
AceGambit

Reputation: 656

Interface seems like the right answer for what you're trying to accomplish. Read up some more on interfaces and polymorphism to fully understand their usage.

Interfaces are correct for you if...

You want any class working with your IInvoice objects to be completely blind to whether the object it's handling an Invoice or CreditNote save for the brief moment when your objects are created.

It looks like you're 90% of the way there, the one thing it seems you're missing is that interfaces are not "instantiated", classes are. so you can have the following method:

public IInvoice CreateInvoice(Request request, int invoiceType)
{
  //380-invoice
  if(Convert.ToInt32(invoiceType) == InvoiceTypeCodeEnumDto.Invoice.Id)
  {
    Invoice model = new Invoice();
    model.RequestId = request.CorrelationId;
    model.SendToCir = "Auto";
    return model;
  }

  //383-creditNote
  if (Convert.ToInt32(invoiceType) == InvoiceTypeCodeEnumDto.CreditNote.Id)
  {
    CreditNote model = JsonConvert.DeserializeObject<CreditNote>  (request.Content)!;
    model.RequestId = request.CorrelationId;
    model.SendToCir = "Auto";
    return model;
  }

  throw new NotImplementedException($"Unexpected invoice type {invoiceType}");
}

and then anywhere in your code you can use

IInvoice myInvoice = CreateInvoice(request, invType);

the only members of myInvoice you'll be able to access are the ones defined on the interface IInvoice. If you want to access the Name property, you'll need to either add it to the IInvoice interface and implement it on both Invoice and CreditNote or you can down-cast your myInvoice object into a concrete type which has the Name property exposed. I don't recommend this approach since the whole point of polymorphism is to remove concrete understanding of the underlying implementation.


Edit: after thinking about your comment I think I understand what you want, let me know if the following makes sense.

You can make just the one model like so:

public class InvoiceMode
{
  public long RequestId{get;set;}
  public string SendToCir {get;set;}
  public string Name{get;set;}
  ... etc
}

and then in your code you can have the following:

public InvoiceModel CreateInvoice(Request request, int invoiceType)
{
  InvoiceModel model;

  //380-invoice
  if(Convert.ToInt32(invoiceType) == InvoiceTypeCodeEnumDto.Invoice.Id)
  {
    model = new Invoice();
  }

  //383-creditNote
  else if (Convert.ToInt32(invoiceType) == InvoiceTypeCodeEnumDto.CreditNote.Id)
  {
    model = JsonConvert.DeserializeObject<CreditNote>  (request.Content)!;
  }

  // Unknown invoice type -- throw error
  else 
  {
    throw new NotImplementedException($"Unexpected invoice type {invoiceType}");
  }
  
  model.RequestId = request.CorrelationId;
  model.SendToCir = "Auto";
  return model;
}

Upvotes: 1

Related Questions