What is the best way to set up an inventory system?

Hey guys,

Recently I’ve been trying to make an inventory system at the moment I have 5 categories of items inheriting from item class and the following way they have been initialized. First off I was wondering if these was a good way to how all items in the first place as I think it would take up a lot of RAM??
public List allItems = new List();

	[SerializeField] Sprite[] weaponImagesInv;
	[SerializeField] Sprite[] armorImagesInv;
	[SerializeField] Sprite[] aidImagesInv;
	[SerializeField] Sprite[] miscImagesInv;
	[SerializeField] Sprite[] ammoImagesInv;

	[SerializeField] Sprite[] weaponImages;
	[SerializeField] Sprite[] armorImages;
	[SerializeField] Sprite[] aidImages;
	[SerializeField] Sprite[] miscImages;
	[SerializeField] Sprite[] ammoImages;

	[SerializeField] GameObject[] bulletPrefabs;

	void Start () {
		allItems.Add(new Weapon(0.000f, "Fists", weaponImagesInv[0], weaponImages[0], 1, 1, Weapon.WepType.Melee, Weapon.WepSubType.None, 1, 1));
		allItems.Add(new Weapon(0.001f, "Swag Ray", weaponImagesInv[1], weaponImages[1], 1, 1, Weapon.WepType.Ranged, Weapon.WepSubType.AssaultRifle, 1, 0.1f, 1, 1, 10, 1, bulletPrefabs[0]));


		allItems.Add(new Armor(1.000f, "Helmet for your Head", null, 1, 1, Armor.ArmorType.Head, 0, 1));
		allItems.Add(new Aid(2.000f, "Name of Some Medicine", null, 1, 1, 1, 1));
		allItems.Add(new Misc(3.000f, "Swagger", null, 1, 1500));    
		allItems.Add(new Ammo(4.000f, "Standard", null, 0, 1));
		allItems.Add(new Ammo(4.001f, "MoreDamage!", null, 0, 5));
	}

Secondly when I try and access the these items I get referred to the item created by the previous way instead of the item in the inventory, this is a result of instances I’m pretty sure but I’m not sure how to fix this issue.

	public List<Item> itemInv = new List<Item>();

public InitialiseItems allInv;
[SerializeField] GameManager gm;
float weight = 0;

public void AddItem(Item i){
		if(itemInv.Contains(i))
			itemInv[itemInv.IndexOf(i)].quantity += i.quantity;
		else{
			itemInv.Add(i);
		}
		gm.DisplayNotification(i.itemName + " was added");
	}
	
	public void RemoveItem(Item i){
		if(itemInv.Contains(i)){			
			if(i.quantity < itemInv[itemInv.IndexOf(i)].quantity){
				itemInv[itemInv.IndexOf(i)].quantity -= i.quantity;
			}
			else{
				itemInv.Remove(i);
			}
			gm.DisplayNotification(i.itemName + " was removed");
		}
	}

Use this code to copy values between two instances.

    using System;
    using System.Reflection;//for copying objects
    using System.Linq;//for string[].Contains()
    using UnityEngine;//for print
    
    public class CopyData {
    	
    	/// <summary>
    	/// Copies the data of one object to another. The target object gets properties of the first. 
    	/// Any matching properties (by name) are written to the target.
    	/// </summary>
    	/// <param name="source">The source object to copy from</param>
    	/// <param name="target">The target object to copy to</param>
    	public static void CopyObjectData(object source, object target)
    	{
    		CopyObjectData(source, target, String.Empty, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    	}
    	
    	/// <summary>
    	/// Copies the data of one object to another. The target object gets properties of the first. 
    	/// Any matching properties (by name) are written to the target.
    	/// </summary>
    	/// <param name="source">The source object to copy from</param>
    	/// <param name="target">The target object to copy to</param>
    	/// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param>
    	/// <param name="memberAccess">Reflection binding access</param>
    	public static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess)
    	{
    		string[] excluded = null;
    		if (!string.IsNullOrEmpty(excludedProperties))
    		{
    			excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    		}
    		
    		MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
    
    		foreach (MemberInfo Field in miT)
    		{
    			string name = Field.Name;
    			
    			// Skip over excluded properties
    			if (string.IsNullOrEmpty(excludedProperties) == false
    			    && excluded.Contains(name))
    			{
    				continue;
    			}
    			
    			
    			if (Field.MemberType == MemberTypes.Field)
    			{
    				FieldInfo sourcefield = source.GetType().GetField(name);
    				if (sourcefield == null) { continue; }
    				
    				object SourceValue = sourcefield.GetValue(source);
    				((FieldInfo)Field).SetValue(target, SourceValue);
    			}
    
    			else if (Field.MemberType == MemberTypes.Property)
    			{
    				PropertyInfo piTarget = Field as PropertyInfo;
    				PropertyInfo sourceField = source.GetType().GetProperty(name, memberAccess);
    				if (sourceField == null) { continue; }
    				
    				if (piTarget.CanWrite && sourceField.CanRead)
    				{
    					object targetValue = piTarget.GetValue(target, null);
    					object sourceValue = sourceField.GetValue(source, null);
    					
    					if (sourceValue == null) { continue; }
    					
    					if (sourceField.PropertyType.IsArray
    					    && piTarget.PropertyType.IsArray
    					    && sourceValue != null ) 
    					{
    						CopyArray(source, target, memberAccess, piTarget, sourceField, sourceValue);
    					}
    					else
    					{
    						CopySingleData(source, target, memberAccess, piTarget, sourceField, targetValue, sourceValue);
    					}
    				}
    			}
    
    		}
    	}
    	
    	private static void CopySingleData(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object targetValue, object sourceValue)
    	{
    		//instantiate target if needed
    		if (targetValue == null
    		    && piTarget.PropertyType.IsValueType == false
    		    && piTarget.PropertyType != typeof(string))
    		{
    			if (piTarget.PropertyType.IsArray)
    			{
    				targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
    			}
    			else
    			{
    				targetValue = Activator.CreateInstance(piTarget.PropertyType);
    			}
    		}
    		
    		if (piTarget.PropertyType.IsValueType == false
    		    && piTarget.PropertyType != typeof(string))
    		{
    			CopyObjectData(sourceValue, targetValue, "", memberAccess);
    			piTarget.SetValue(target, targetValue, null);
    		}
    		else
    		{
    			if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName)
    			{
    				object tempSourceValue = sourceField.GetValue(source, null);
    				piTarget.SetValue(target, tempSourceValue, null);
    			}
    			else
    			{
    				CopyObjectData(piTarget, target, "", memberAccess);
    			}
    		}
    	}
    	
    	private static void CopyArray(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object sourceValue)
    	{
    		int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null);
    		Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength);
    		Array array = (Array)sourceField.GetValue(source, null);
    		
    		for (int i = 0; i < array.Length; i++)
    		{
    			object o = array.GetValue(i);
    			object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
    			CopyObjectData(o, tempTarget, "", memberAccess);
    			targetArray.SetValue(tempTarget, i);
    		}
    		piTarget.SetValue(target, targetArray, null);
    	}
    }

Use it like this:

Item newItem = new Item();
CopyData.CopyObjectData(ItemTemplate, newItem);