Retrieving values from list of Scriptable Objects

I’m trying to make a composition-based inventory after reading some forums on here and watching some tutorials and talks on youtube but I am not sure I am doing it right, or at least elegantly.
I have a large list of item attribute scriptable objects, i.e.

 public class Damage : ItemAttribute 
`{    
        public int damage;
    }

They are all inheriting from ItemAttribute SciptableObject which just has a virtual void DoLayout().
So I have loads of those that I can apply as and when needed on items…

public enum ItemType { CONSUMABLE, WEAPON, EQUIPMENT }
[CreateAssetMenu (menuName = "Item/Item")]
public class Item : ScriptableObject {

    public ItemType itemType;

    public List<ItemAttribute> attributes = new List<ItemAttribute>();        
}

These are compiled into Inventories:

public class InventorySO : ScriptableObject 
{
    public List<Item> items = new List<Item>();    
}

Which then go into the Inventory Manager…

public class InventoryManager : MonoBehaviour {

    public InventorySO charInventory;    
    void Start()
    {
        for (int i = 0; i < charInventory.items.Count; i++)
        {
            if (charInventory.items *!= null)*

{
Item tmp = charInventory.items*;*
Debug.Log(“Item” + tmp.name);
var weapons = tmp.attributes.Where(ItemAttribute => ItemAttribute.GetType() == typeof(Damage));
foreach (Damage damage in weapons)
{
Debug.Log("Damage: " + damage.damage);
}
var names = tmp.attributes.Where(ItemAttribute => ItemAttribute.GetType() == typeof(ItemName));
foreach (ItemName name in names)
{
Debug.Log("Name: " + name.itemName);
}
}
else
{
Debug.Log(“Empty”);
}
}
}
}
I’m going to use the inventory manager to get all the information stored in the items attributes but if I have to do that linq statement and foreach loop for every possible attribute in every item it is going to get very messy. Is there another way to do this? Is this even a good way to create an inventory? I plan of duplicating this system for skills/abilities if this works out

If you really need this level of flexibility, then the overhead of the system is acceptable, as long as the number of attributes on an item is relatively small (e.g. below 100).

Instead of using Linq, which will allocate from the heap (cause more GC collections), implementing a simple helper method will make access to the attributes easier. In your Item class:

public TAttr Attribute<TAttr>()
    where TAttr : ItemAttribute {

    TAttr attr = null;
    
    var count = attributes.Count;
    for (int i = 0; i < count; i++) {
        attr = attributes *as TAttr;*

if (attr != null) return attr;
}

attr = ScriptableObject.CreateInstance();
attributes.Add(attr);

return attr;
}
Then you can write code like this:
item.Attribute().damage = 42;
var damage = item.Attribute().damage;