有没有一种方法可以使用在具有两个结构不同的记录的数组上工作的单个类?

时间:2019-05-10 01:19:49

标签: c# arrays struct

我希望使用ListClass的类方法从输入文件中读取并将输入的数据存储到结构数组中。我已经做了。然后,我希望从一个格式与第一个文件不同的单独文件读入一个单独的数组,但使用相同的ListClass。这可能吗?

我尝试使用抽象类,但似乎不太正确。一个小例子:

 class ListClass 
 {           
     public struct struct1
     {
         public string strPart;
         public string strDescrip;
         public int intQty;
     }  

     public struct struct2
     {
         public string strPart;
         public char chrSold;
         public int intQtySold;
     }

     public int MAX_ELEMENTS = 4;

     //PRIVATE DATA MEMBERS
     private arr[] listArr;
     private int length;
     private int currPos;

     public ListClass()
     {
         length = 0;
         currPos = 0;
         listArr = new arr[MAX_ELEMENTS];
     }


     public ListClass(int size)
     {
         listArr = new Array[size];
     }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Create a deep copy of the list
    //Pre:      List has been instantiated and orig contains list to be copied
    //Post:     An identical, deep copy of the list has been created.
    public ListClass(/*in*/ ListClass orig) //list to be copied
    {
        length = orig.length;
        //currPos = orig.currPos;

        // Allocate the new list
        listArr = new Array[MAX_ELEMENTS];

        // Copy over all the values
        for (int i = 0; i < MAX_ELEMENTS; i++)
            listArr[i] = orig.listArr[i];
    }//end copy constructor


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Indicates whether or not the list is empty
    //Pre:      List has been instantiated
    //Post:     Returns true if list is empty and false, otherwise
    public bool IsEmpty()
    {
        return (length == 0);
    }//end IsEmpty


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Indicates whether or not the list is full
    //Pre:      List has been instantiated
    //Post:     Returns true if list is full and false, otherwise
    public bool IsFull()
    {
        return false;
    } //end IsFull


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Inserts item into the list
    //Pre:      List is not full
    //Post:     Item has been inserted at the end of the current list, length has 
    //          been modified 
    //Error Handling:
    //          if the key already exists within list, do not insert newItem and return false 
    //          if the list is full, do not insert the item and return false

    public void Insert(/*in*/ Array newItem)        //item to be added
    {
        // Make sure there is space
        if (NeedToExpand())
            //Expand if needed and insert new item
            Expand();

        listArr[length] = newItem;
        length++;
    } //end Insert


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Deletes an item from the list
    //Pre:      Method Find has been called to find the item to delete, and the 
    //          that item is in the list.CurrPos now points at the item to be deleted
    //Post:     The item denoted by currPos has been deleted from the list, lemgth has
    //          been updated.
    //Error Handling: If the list is empty, no changes are made
    public void Delete(string key)
    {
        if (IsEmpty())
            Console.WriteLine("List is Empty");
        else
        {
            if(!Find(key))
                Console.WriteLine("Item not Found");
            else
            {
                if (length > 0)
                {
                    for (int i = currPos; i < length; i++)
                        listArr[i] = listArr[i + 1];

                    length--;
                }

                if (NeedToShrink())
                    Contract();
            }
        }
    }//end Delete


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Moves to the beginning of the list
    //Pre:      List has been instantiated
    //Post:     currPos has been set to the first position in the list
    public void FirstPosition()
    {
        currPos = 0;
    }//end FirstPosition


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Moves to the next element in the list
    //Pre:      List has been instantiated
    //Post:     currPos has been moved to the next position in the list
    //Error Handling: if currPos is already at the end of the list, currPos is not modified
    public void NextPosition()
    {
        if (!EndOfList())
            currPos++;
        else
            Console.WriteLine("End of List");
    } //end NextPosition


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Determines if currPos is at the end of the list
    //Pre:      List has been instantiated
    //Post:     Returns true if currPos is at the end of the list, and false, otherwise
    //          end-of-list denotes the first empty index in the list.

    public bool EndOfList()
    {
        return (currPos == length - 1);
    }//end EndOfList


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~        


    //Purpose:  Determines whether or not item is in the list
    //Pre:      item is assigned a value
    //Post:     If item is in the list then true is returned  and currPos contains
    //                the index of the item in the list, otherwise, 
    //                false is returned and currPos is at zero.
    public bool Find(/*in*/ string key)     // item to be found
    {
        bool found = false;
        currPos = 0;

        while (!found && currPos < length)
        {
            if (listArr[currPos] == key)
                found = true;
            else
                currPos++;
        }// End while

        if (!found)
            currPos = 0;

        return found;
    }//end Find


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose:  Returns the current item in the list(denoted by currPos)
    //Pre:      List is not Empty
    //Post:     Returns the item at currPos
    //Error Handling: if Retrieve is called on an empty list an InvRec with a key set 
    //                  to int.MinValue is returned. 
    public object Retrieve()
    {
        object inv = new object();

        if (!IsEmpty())
            return listArr[currPos];
        else
        {
            Console.WriteLine("The list is empty");
            return inv;
        }

    }//end Retrieve


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //Purpose: Clears the list
    //Pre: List has been instantiated
    //Post: List has been restored to its initial condition
    public void Clear()
    {
        currPos = 0;
        length = 0;
    }//end Clear

    //Purpose: indicates if the list needs to be expanded
    //Pre: insert must be called with a new item to insert
    //Post: returns true if length equals MAX_ELEMENTS, false otherwise
    private bool NeedToExpand()
    {
        if (length == MAX_ELEMENTS)
            return true;
        else
            return false;
    }

    //Purpose: indicates if the list needs to be shrunk
    //Pre: delete must be called with a item to delete
    //Post: returns true if length is 25% of MAX_ELEMENTS, false otherwise
    private bool NeedToShrink()
    {
        if ((float)MAX_ELEMENTS * 0.25f == length)
            return true;
        else
            return false;

    }

    //Purpose: to expand the space of the list
    //Pre: NeedToExpand must return true
    //Post: the size of the list is doubled
    private void Expand()
    {
        MAX_ELEMENTS *= 2;

        ListClass tempList = new ListClass(MAX_ELEMENTS);

        for (int i = 0; i < length; i++)
            tempList.listArr[i] = listArr[i];

        listArr = tempList.listArr;
    }

    //Purpose: to contract the size of the list
    //Pre: NeedToContract must return true
    //Post: the size of the list is shrunk
    private void Contract()
    {
        if(MAX_ELEMENTS != 4)
        {
            MAX_ELEMENTS /= 2;

            ListClass tempList = new ListClass(MAX_ELEMENTS);

            for (int i = 0; i < length; i++)
                tempList.listArr[i] = listArr[i];

            listArr = tempList.listArr;
        }            
    }

该代码段是否有意义。我有两种格式不同的结构。我想使用每个ListClass中的所有方法存储到数组中。

2 个答案:

答案 0 :(得分:0)

好的,好吧……鉴于此帖子标有C#标记,我建议使用一种C#常规的方法。

首先,C#内置了很多集合,因此通常不会尝试重新编写它们。还有一点,Struct1和Struct2的类型不同,似乎它们具有不同的含义-我们可以将它们重命名为InventoryAmount和SoldAmount。

所以您只需要在主类中声明两个列表,像这样

using System.Collections.Generic;
...
List<InventoryAmount> InventoryAmounts { get; } = new List<InventoryAmount>();
List<SoldAmount> SoldAmounts { get; } = new List<SoldAmount>();

然后,您读入数组,然后将其添加到列表中,如下所示:

InventoryAmount[] inventoryAmounts = ...
this.InventoryAmounts.AddRange( inventoryAmounts); 

SoldAmount[] soldAmounts = …
this.SoldAmounts.AddRange( soldAmounts);

实际上,这种方法会分配一些额外的内存,因为将数组添加到列表后不使用它们。您可以通过将每个值在读取时直接放入列表中来避免这种情况。或者,您可以将它们留在数组中。

另一条评论:像FirstPosition,NextPosition这样的方法通常是使用Enumerator和Enumerable完成的。这些内置于List类和数组中,并由“ foreach”使用,如下所示:

foreach (InventoryAmount ia in this.InventoryAmounts) {
   ...
}

foreach (InventoryAmount ia in inventoryAmounts) {
   ...
}

答案 1 :(得分:0)

响应您的评论,我真的不建议继续使用ListClass代码。最好利用c#内置的列表。

另一方面,如果您真的决心以艰难的方式(即可能是错误的方式)这样做,那么我该阻止谁?

完成此操作的两种最困难的方法是(a)声明可以包含InventoryAmount或SoldAmount的结构,或者(b)将该数组声明为object []并使用c#装箱。从业务角度来看,这两种方法都可能毫无意义,而且效率也不高。

对于第一种方法(a),只需声明一个联合结构,例如:

public struct InventoryAmountOrSoldAmount 
{
    public InventoryAmountOrSoldAmount( InventoryAmount ia => this.InventoryAmount = ia;
    public InventoryAmountOrSoldAmount( SoldAmount sa => this.SoldAmount = sa;
   public InventoryAmount { get;}
   public SoldAmount { get;}
}

然后将其用作数组的类型:

private InventoryAmountOrSoldAmount[] listArr = new InventoryAmountOrSoldAmount[MAXELEMENTS];

或者第二种方法(b)是这样声明数组:

private object[] listArr = new object[MAXELEMENTS];

然后,您可以为数组的每个元素分配一个InventoryAmount或SoldAmount。 C#通过将一个副本放在堆上并将其指针放在数组元素中来对结构进行包装。