Since you've mentioned its name in one of the comments here, I assume you are aware of [Entity Component System](https://en.wikipedia.org/wiki/Entity_component_system) modeling, so I won't delve too much into the specifics.

If you want runtime coupling of components, as opposed to design-time coupling, then a logical consequence here is that you're going to have to look these components up during runtime as well. You can't rely on a class definition to already know whether your entity has a component (or not), since that wasn't yet known at design time.

At design time, all you know is that your entity can contain components. You don't know which ones, and whenever you try to access one you have to manually check if there is one to be accessed. These are all givens based on the requirements you've defined.

> My first thought was have each component register the to the Player object and store them in a HashSet<IComponent> but if I use an interface for the polymorphic benefits to add them to a collection theres not really much else in common with them and I would have to loop through the hash set every time to check if for example the HealthComponent exists and then if it does, cast it from the interface to the type required and call the Damage() function.

That is precisely what you're going to have to do. **Your requirements have forced this design.**

Like I established before, given your requirements there's no way to pre-emptively know whether an entity contains a component of a given type. This is specifically what you requested by having runtime coupling. Therefore, the code you write during design time cannot possible account for specific component types.

If it could account for specific types, then that is _by definition_ design-time coupling. If this is the case, then Ewan's answer of using (design-time) composition is the better approach. The rest of my answer presumes that this is not what you want.

> This does not seem like a smart approach to me, lots of loops every single time, as well as type checking and casting. Is this actually how people do component based systems to allow for a more decoupled setup?

But that doesn't mean your code cannot be improved on. 

* Instead of using a generic collection type, you can derive a component collection which extends several features related to finding components.
  * It's often better to use composition instead of inheritance when creating a custom collection class, but this is one of the cases where inheritance is acceptable because you'll still want the ability to treat is as the base collection that it is. If you disagree, use composition instead.
  * I'm using `List<T>` in my example, but feel free to use any other collection type you prefer.
* Instead of iterations, you can use LINQ. That's still using iterations behind the scenes, but it keeps your code easier to read. 
  * Note also that LINQ uses `yield return` behavior, i.e. it does not iterate the entire collection unless it has to.

Your code could for example be rewritten to:

    public class ComponentList : List<IComponent>
    {
        public IEnumerable<TComponent> Get<TComponent>() where TComponent : IComponent
        {
            return this
                    .Where(x => x is TComponent)
                    .Select(x => x as TComponent);
        }

        public void UpdateAll<TComponent>(Action<TComponent> updateAction)
             where TComponent : IComponent
        {
            foreach(var component in Get<TComponent>()
            {
                updateAction(component);
            }
        }

        public void Update<TComponent>(Action<TComponent> updateAction)
             where TComponent : IComponent
        {
            var component = Get<TComponent>().SingleOrDefault();
            
            if(component != null)
                updateAction(component);
        }

        public void TryUpdate<TComponent>(Action<TComponent> updateAction)
             where TComponent : IComponent
        {
            var component = Get<TComponent>().Single();
            
            updateAction(component);
        }
    }

And then your entity contains a property of this type:

    public class Player
    {
        public ComponentList Components { get; set; }
    }

And then you can use the nice premade functions that look up the component for you.

    Player player = GetPlayerEntity();

    // If player is expected to have a HealthComponent
    player.Components.Update<HealthComponent>(c => c.ReduceHealth(30));

    // If you're not sure if player has a HealthComponent
    player.Components.TryUpdate<HealthComponent>(c => c.ReduceHealth(30));

    // If player can have multiple HealthComponents
    player.Components.UpdateAll<HealthComponent>(c => c.ReduceHealth(30));

This is just a rudimentary example. Depending on whether your entities can have 0/1/many components of a given type, the implementation will vary.

But the main takeaway here is that you can create some helper methods which will do the component lookup for you, so that you don't have to constantly write the same logic over and over. And instead you can focus solely on what you're trying to do with this component (in my example, `c.ReduceHealth(30)`).