简体   繁体   中英

List<CustomClass> sent as List<T>; how to get the properties?

I have this piece of code

 public class Ticket
    {
        public string strArticleID { get; set; }
        public string strArticleDescription { get; set; }
        public decimal decArticlePrice { get; set; }
        public decimal decArticleVAT { get; set; }
        public decimal decArticuleNetPrice { get; set; }
        public decimal decArticleDiscount { get; set; }
        public decimal decArticleQuantity { get; set; }

    }
    public static List<Ticket> _lstCurrentTicket = new List<Ticket>();

That I want so send to an external DLL to get all the lines in _lstCurrentTicket to print a ticket through

for (int i = 0; i < dataGridView1.Rows.Count; i++)
        {
            Ticket ticket = new Ticket();

            string strRefID = this.dataGridView1.Rows[i].Cells[0].Value.ToString();
            string strDescription = this.dataGridView1.Rows[i].Cells[1].Value.ToString();
            decimal decQuantity = (decimal)this.dataGridView1.Rows[i].Cells[2].Value;
            decimal decUPrice = (decimal)this.dataGridView1.Rows[i].Cells[3].Value;
            decimal decDiscount = Convert.ToDecimal(this.dataGridView1.Rows[i].Cells[4].Value.ToString().Substring(0, this.dataGridView1.Rows[i].Cells[4].Value.ToString().Length - 1));
            decimal decVAT = Convert.ToDecimal(this.dataGridView1.Rows[i].Cells[5].Value.ToString().Substring(0, this.dataGridView1.Rows[i].Cells[5].Value.ToString().Length - 1));
            decimal decGPrice = (decimal)this.dataGridView1.Rows[i].Cells[6].Value;


            ticket.strArticleID = strRefID;
            ticket.strArticleDescription = strDescription;
            ticket.decArticlePrice = decUPrice;
            ticket.decArticleVAT = decVAT;
            ticket.decArticuleNetPrice = decGPrice;
            ticket.decArticleDiscount = decDiscount;
            ticket.decArticleQuantity = decQuantity;

            _lstCurrentTicket.Add(ticket);
        }


 TicketPrinting tktPrint = new TicketPrinting ();
 //Ticket and copies
 tktPrint.PrintTicketFromList(_lstCurrentTicket, 2);

Since it is an external DLL, I thought the easiest way to work with it in target DLL was

 public void PrintTicketFromList<T>(List<T> lstArticles, short intCopies)
    {            
        foreach (var prop in lstArticles.GetType().GetProperties())
        {

            if (prop.Name == "Item")
            {
                //Copy external list to local class for printing

            }
        }...

But I'm stuck there. How can I iterate each property and value from each original class in the list so I can copy it? If I make a breakpoint I can see that the fields and values are correctly passed, but I do not get how to access them so I can do something like creating a local class exactly like the original and clone the list (and if I try it will say local list(Ticket) and passed List(T) are not the same type).

Or how could I copy it if I create an exact class in the target and do something like

public void PrintTicketFromList(object lstArticles, short intCopies)
    {
        List<TargetDLLTicket> lst =((List<TargetDLLTicket>)lstArticles).ToList(); }

Any thoughts?

It sounds like you have a circular dependency issue. You need to move the types you are sending to your print function to a common assembly (new project) that is then referenced by both the calling project and your print project. Then both projects can access this shared type.

A note about your design. The way you are going about this is probably not good to begin with thus your error. The actual printer function should not have to know anything about the types passed in. A good rule of thumb is to try to make your code as loosly coupled as possible. A better idea is to create an Interface that takes care of writing to the printer canvas (or something like that, you did not provide your printer code so this is a guess) and the printer function can call that method on the incoming object. The printer method should then also only accept that interface as a parameter. This is based on a Visitor pattern. Here is an example.

public interface IPrintable {
   void WriteToPrinter(PrinterCanvas canvas);
}

public class Printer {
   public void Print(IPrintable somethingToPrint) {
      var canvas = getCanvas();
      somethingToPrint.WriteToPrinter(canvas);
   }
}

If at any point possible you should try to avoid reflection like Igor does in his answer.

But if you really want to use reflection you are currently not inspecting the item but the list of items.

You should try something like (writing this from memory):

public void PrintTicketFromList<T>(List<T> lstArticles, short intCopies)
{   
    foreach (var item in lstArticles)
    {
        foreach (var prop in typeof(T).GetProperties())
        {
            var value = prop.getValue(item);
        }
    }
}

Instead of List<T> create an interface, ITicket for example and accept List<ITicket> . Using List<T> as a generic whenever you know you only can work with something that is a Ticket is creating an unnecessary wide range of potential inputs. Using an interface allows you to not worry about the concrete implementation, and instead get at only what your dll is concerned with, the contract.

You could put the interface in one of two places, either another external common assembly that both of your assemblies reference, or you could put the interface into your assembly that has the ticket printing logic. Your Ticket class could then implement the interface.

An example of what this could look like:

public interface ITicket
{
   //properties and methods you want to have all implementations to contain.
}

public class Ticket : ITicket
{
}

public class LastTicket :ITicket
{
}

public void PrintTicketFromList(List<ITicket> lstArticles, short intCopies)
{
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM