locked
how to use multiple of the same object? RRS feed

  • Question

  • User-1225226813 posted

    Hi all, 

    I've got this problem that I've not come across before and I want to seek some advice. 

    I’ve consumed a wsdl and xsd files into a project, performed a search on the API and returned the XML. Stored the XML in SQL and de-serialised it to I can use it in my aspx form.

    Part of this, I'm working with an array of objects, and each object inside can be of a different class object. (84 of them)

    Now, the fields inside these are pretty much the same. Contain the same fields such as name, account no, phone number etc.

    As you can see below, I’ve got a simple way of getting the type of the array item and calling an appropriate method for that type.

    There must be an easier way to cast the type so I don’t have to write out and maintain 84 methods doing the same thing?

    Any help or pointers would be appreciated.

    Thanks Dave

     

     

    MainAccount ins = sspPer2.Siteaccount[i].Mainaccount;

    Int32 ic = ins.Items.Length;

    for (int q = 0; q < ic; q++) { var obj = ins.Items[q].GetType();

    if (obj.ToString() == "CarAccount") { litShowResults.Text += CarAccount(ins, q); }

    if (obj.ToString() == "BikeAccount") { litShowResults.Text += BikeAccount(ins, q); }

    if (obj.ToString() == "PlaneAccount") { litShowResults.Text += PlaceAccount(ins, q); }

    etc..

     

    private string BikeAccount (mainAccount ins, Int32 q)

        {

            UseBike ins1 = (UseBike)ins.Items[q];

    string fullname = ins1.Name ;

    string amount = ins1.amount;

           }

     

    private string CarAccount (mainAccount ins, Int32 q)

        { 

            useCar ins1 = (useCar)ins.Items[q];

    string fullname = ins1.Name ;

    string amount = ins1.amount;

           }

     

    Sunday, October 27, 2019 7:27 PM

All replies

  • User-719153870 posted

    Hi DDH01,

    so I don’t have to write out and maintain 84 methods doing the same thing?

    If i didn't misunderstand anything, this is where you want to use the C# Generics.

    Please check below demo:

    ASPX:

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
                <asp:Label ID="Label2" runat="server" Text="Label"></asp:Label><br />
                <asp:Label ID="Label3" runat="server" Text="Label"></asp:Label>
                <asp:Label ID="Label4" runat="server" Text="Label"></asp:Label>
            </div>
        </form>
    </body>
    </html>

    CS:

    protected void Page_Load(object sender, EventArgs e)
            {
                UseBike bike = new UseBike();
                bike.fullname = "bike1";
                bike.amount = 11;
    
                useCar car = new useCar();
                car.fullname = "car1";
                car.amount = 22;
    
                Label1.Text= WhatAccount<UseBike>(bike, "fullname");
                Label2.Text = WhatAccount<UseBike>(bike, "amount");
                Label3.Text = WhatAccount<useCar>(car, "fullname");
                Label4.Text = WhatAccount<useCar>(car, "amount");
            }
    
            public static string WhatAccount<T>(T t,string property)
            {
                return t.GetType().GetProperty(property).GetValue(t, null).ToString();
            }
    
            public class UseBike
            {
                public string fullname { get; set; }
                public int amount { get; set; }
            }
    
            public class useCar
            {
                public string fullname { get; set; }
                public int amount { get; set; }
            }

    Here's the result:

    Hope this could help.

    Best Regard,

    Yang Shen

    Monday, October 28, 2019 6:35 AM
  • User-1225226813 posted

    Thank you for the response Yang Shen, 

    That's a neat way to returning a  generic property value, and will use that, but it doesn't help me with the my current problem. 

    that method would still mean i need to write out all fields for 84 methods.

    i was hoping there would be a way to cast the whole class into one generic class?

    something like this, (i know the sample below wont work, but might help explain what im trying to.)

    string outv = "";
    // get the class type used for the item
    var obj = ins.Items[q].GetType();
    // define a null object
    object ins1 = null;
    // if the object is secured, then use the secured class
    if (obj.ToString() == "secured") {
    ins1 = (Unsecured)ins.Items[q];
    }

    if (obj.ToString() == "bike") {
    ins1 = (bike)ins.Items[q];
    }
    // now get the property from that object.
    string companyname = Common.Nullchk(ins1.companyClass);

    thanks in advance

    Dave

    Monday, October 28, 2019 9:01 AM
  • User-719153870 posted

    Hi DDH01,

    It's little hard to understand the requirement still.

    Maybe you could provide what are these two things? MainAccount ins = sspPer2.Siteaccount[i].Mainaccount;

    It seems you want this method to define which class in setting as the parameter instead of setting a specific class as the parameter manually?

    Then more code about above two things(class? list?) will help a lot understading the current situation.

    Best Regard,

    Yang Shen

    Monday, October 28, 2019 9:43 AM
  • User-1225226813 posted

    Hi Yang Shen

    its a very large XML data structure of 10k lines  and buried far down inside it is this section i'm trying to iterate out the data to a report.

    the sspPer2 and MainAccount are just a section within it,  an object reference to a class that specifies that part of the XML element

    just as a small snippet, i have created a cutdown simple version

    <?xml version="1.0" encoding="utf-16"?>
    <credit>
    <client>abcdef</client>
    <solesrc>
    <primary>
    <er>
    </er>
    <IDp>
    </IDp>
    <adr>
    <Insight>
    <Bikes>
      <accountNo>123456</accountNo>
      <name>
        <first>Dave</first>
        <middle>Dave</middle>
        <surname>Dave</surname>
       </name>
       <balance>123</balance>
       <prodage>123</prodage>
    </Bikes>
    <cars>
        <accountNo>123456</accountNo>
        <name>
          <first>Dave</first>
          <middle>Dave</middle>
          <surname>Dave</surname>
       </name>
       <balance>123</balance>
       <prodage>123</prodage>
    </cars>
    <cars>
        <accountNo>123456</accountNo>
         <name>
            <first>Dave</first>
            <middle>Dave</middle>
            <surname>Dave</surname>
         </name>
         <balance>123</balance>
         <prodage>123</prodage>
    </cars>
    <cars>
        <accountNo>123456</accountNo>
        <name>
         <first>Dave</first>
         <middle>Dave</middle>
         <surname>Dave</surname>
        </name>
        <balance>123</balance>
        <prodage>123</prodage>
    </cars>
    <planes>
        <accountNo>123456</accountNo>
        <name>
          <first>Dave</first>
          <middle>Dave</middle>
          <surname>Dave</surname>
        </name>
        <balance>123</balance>
        <prodage>123</prodage>
    </planes>
    </Insight>
    <adr>
    </primary>
    </solesrc>
    </credit>

    As you can see in the XML path we have the following nodes.

    Credit.Primary.Insight[].Bike

    Credit.Primary.Insight[].Car

    Credit.Primary.Insight[].Plane

    Each of these have their own Class (Bike, Car, Plane) within the XSD that define what fields are within that node.

    i'm trying to loop around all entries in Credit.Primary.Insight[], identify what the node class is within it and pass that to one method where i can then specify that class for the given node and loop the contents out to the report.

    Below is the code i'm currently using to loop each of these, but i dont want to have to write or maintain 84 different methods that all do the same thing (apart from specify the class that is being used)

    //================================================================================================
    //= APPLICANT 1
    //================================================================================================
    Int32 addrCount = sspPer.suppliedAddressData.Length;
    // insight data.
    for (int i = 0; i < addrCount; i++)
    {

    if (sspPer.SAD[i].addressSpecificData.insight != null) {

    InsightContainer ins = sspPer.SAD[i].addressSpecificData.insight;
    Int32 insightCount = ins.Items.Length;
    for (int q = 0; q < insightCount; q++)
    {
    var obj = ins.Items[q].GetType();

    // rather then specifying each of the 84 types,
    //i want a generic way of calling one method to gather the dtails
    // litShowResults.Text += genericCall(ins, q, obj.ToString());

    switch (obj.ToString())
    {
    case "EC.Comms":
    litShowResults.Text += CommsVal(ins, q);
    break;
    case "EC.CC":
    litShowResults.Text += CCVal(ins, q);
    break;
    case "EC.CA":
    litShowResults.Text += CAVal(ins, q);
    break;
    case "eEC.MO":
    litShowResults.Text += MOVal(ins, q);
    break;
    case "EC.SL":
    litShowResults.Text += SLVal(ins, q);
    break;
    case "EC.USL":
    litShowResults.Text += USLVal(ins, q);
    break;

    // etc.. for 84 versions

    default:
    litShowResults.Text += MissingEntry(ins, q);
    break;
    }
    }
    }
    }


    private string USLVal(InsightContainer ins, Int32 q)
    {

    // here i specify what class it being used to define this type of data.

         Unsecured ins1 = (Unsecured)ins.Items[q];


         //ins1.GetType().GetMethod("unsecured").Invoke(ins1, null);

         var obj = ins.Items[q].GetType();
         string type1 = "TYPE:" + obj.ToString();
        string companyname = Common.Nullchk(ins1.companyClass);

    }

    Monday, October 28, 2019 10:21 AM
  • User-719153870 posted

    Hi DDH01,

    Sorry haven't replied for such a long time, i tried to build a simple similar demo but failed.

    The code you provided is still even harder to understand and the requirement becomes vague.

    switch (obj.ToString())
    {
    case "EC.Comms":
    litShowResults.Text += CommsVal(ins, q);
    break;
    case "EC.CC":
    litShowResults.Text += CCVal(ins, q);
    break;
    case "EC.CA":
    litShowResults.Text += CAVal(ins, q);
    break;
    case "eEC.MO":
    litShowResults.Text += MOVal(ins, q);
    break;
    case "EC.SL":
    litShowResults.Text += SLVal(ins, q);
    break;
    case "EC.USL":
    litShowResults.Text += USLVal(ins, q);
    break;

    // etc.. for 84 versions

    default:
    litShowResults.Text += MissingEntry(ins, q);
    break;
    }
    }
    }
    }

    My current thought is that you want to simplify code above, right? 

    The whole business process is like when you go through all the ins.Items, check which class it is and convert it, then use the generic method to return what you want.

    In this part of code, you mean you need to write 84 different methods (like CommsVal,CCVal, etc..) for similar function, but the generic method i provided earlier should have solved this problem, you will only need to use it like:  WhatAccount<Unsecured>(ins.Items[q], "fullname"); after you identify which kind of class the ins.Items[q] is.

    Or, Are you trying to return different string value from the generic method in different cases? For example, if it's car, you want the method return fullname, if it's bike, you will want it return firstname instead? If so, you will just need to change the "property" parameter in the generic method.

    I was trying to build a complete demo which includes an xml file and loop through the xml and the method i provided but failed because:

    1. We don't know what InsightContainer is, a customer class? a node list?
    2. Hard to understand what is sspPer.suppliedAddressData. How to create these two things.

    We will need more information to understand your code , sorry for any inconvenience.

    Best Regard,

    Yang Shen

    Tuesday, October 29, 2019 8:35 AM
  • User-1225226813 posted

    thank you again for your reply Yang Shen,
    I really do appreciate your help!
    yes, i'm trying to avoid having to write out the same code 84 times.
    The Bike , Car and plane classes are just 3 examples of the 84 classes, but they all contain the same properties (e.g. name, accountNo, Balance, etc)

    Just as an example below, this is what i'm trying to achieve.

    As I loop the class type in (ins.Items[]), that that name to another class where i can assign the correct class to it, then take out the properties/ values.


    private void Test1() {
    // lots of other code up here to get to this point..
    // i wont write it all out as there is too much.

    InsightContainer ins = sspPer.SAD[i].addressSpecificData.insight;
    Int32 insightCount = ins.Items.Length;
    for (int q = 0; q < insightCount; q++)
      {
        // i have the class type below in obj
        var obj = ins.Items[q].GetType();
        loopTheContent(ins, obj);
      }


    }


    private void loopTheContent(InsightContainer ins, string objName) {

      var UseClass = null;

      if (objName == "Car") {
       UseClass = new Car;
      }
      if (objName == "Bike")
      {
       UseClass = new Bike;
      }
      if (objName == "Plane")
      {
       UseClass = new Plane;
      }

       UseClass ins1 = (UseClass)ins.Items[q];

       //ins1.GetType().GetMethod("unsecured").Invoke(ins1, null);
       var obj = ins.Items[q].GetType();
       string type1 = "TYPE:" + obj.ToString();
       string companyname = Common.Nullchk(ins1.companyClass);

    }

    Tuesday, October 29, 2019 8:52 AM
  • User-719153870 posted

    Hi DDH01,

    It seems the main issue is caused by your 84 same classes with different names.

    Are you willing to change your xml schema?

    For example:

    <Insight>
    <Vehicles>
    <Vtype>Bikes</Vtype>
    <accountNo>123456</accountNo>
      <name>
        <first>Dave</first>
        <middle>Dave</middle>
        <surname>Dave</surname>
       </name>
       <balance>123</balance>
       <prodage>123</prodage>
    </Vehicles>
    <Vehicles>
    <Vtype>Cars</Vtype>
    <accountNo>123456</accountNo>
      <name>
        <first>Dave</first>
        <middle>Dave</middle>
        <surname>Dave</surname>
       </name>
       <balance>123</balance>
       <prodage>123</prodage>
    </Vehicles>
    <Vehicles>
    <Vtype>Plane</Vtype>
    <accountNo>123456</accountNo>
      <name>
        <first>Dave</first>
        <middle>Dave</middle>
        <surname>Dave</surname>
       </name>
       <balance>123</balance>
       <prodage>123</prodage>
    </Vehicles>
    </Insight>

    In this case, after you deserialized your xml, it will generate only one class--"Vehicles".

    Then you can use the method like below in your loop through ins.Items[q]:

    public static string WhatAccount<T>(T t,string property)
            {
                string Type= t.GetType().GetProperty("Vtype").GetValue(t, null).ToString();//Car, bike, Plane...
                return t.GetType().GetProperty(property).GetValue(t, null).ToString();//return whichever property(s) you want
            }
    
    //below you can call this method in your event
    
    Vehicles ins1 = (Vehicles)ins.Items[q];
    
    string t = WhatAccount<Vehicles>(ins1,"fullname");

    This should be more simple than 84 classes.

    Best Regard,

    Yang Shen

    Wednesday, October 30, 2019 7:10 AM