How to add components to entity without calling generic method?

How can I add components to entity without knowing exact type of IComponentData/ISharedComponentData? For example, I have List<IComponentData> how can I add all of those to the entity? I already did a workaround and created new interface with AddToEntity method which has to be implemented by every component but that’s a lof of boilerplate if I need to implement it for EntityManager, EntityCommandBuffer and EntityCommandBuffer.ParallelWriter.

I can think of a way that would work fast on platforms that allow Reflection.Emit (PC, WiiU, and Android). If those are the only platforms you’re targeting, then you basically want something that generates and calls the appropriate method. Something like this (not tested; I just typed it here in the forum):

public static void AddAnyComponent(EntityManager em, Entity e, IComponentData c)
{
    Type cType = c.GetType();
    if(!addComponentCache.TryGetValue(cType, out var action))
    {
        action = GenerateSetComponentDelegate(cType);
        addComponentCache[cType] = action;
    }
    action(em, e, c);
}

private static readonly Dictionary<Type, Action<EntityManager, Entity, IComponentData>>() addComponentCache
    = new Dictionary<Type, Action<EntityManager, Entity, IComponentData>>();
private static readonly MethodInfo addComponentGenericMethod = FindAddComponentGenericMethod();

private static MethodInfo FindAddComponentGenericMethod() =>
    typeof(EntityManager)
        .GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
        .Where(m =>
        {
            // this part might be a bit wrong; I did it from memory
            if(m.Name != "AddComponent" || !m.ContainsGenericParameters) return false;
            ParameterInfo[] p = m.GetParameters();
            return p.Length == 2 && p[0].Type == typeof(Entity);
        }).First();

private static Action<EntityManager, Entity, IComponentData> GenerateSetComponentDelegate(Type cType)
{
    MethodInfo methodInstance = addComponentGenericMethod.MakeGenericMethod(cType);
    ParameterExpression paramEm = Expression.Parameter(typeof(EntityManager), "em");
    ParameterExpression paramE = Expression.Parameter(typeof(Entity), "e");
    ParameterExpression paramC = Expression.Parameter(typeof(IComponentData), "c");
    Expression castC = Expression.Convert(paramC, cType); // i forget exactly how to cast; this might be wrong
    Expression call = Expression.Call(paramEm, methodInstance, paramE, castC);
    LambdaExpression lambda = Expression.Lambda<Action<EntityManager, Entity, IComponentData>>(call, paramEm, paramE, paramC);
    return lambda.Compile();
}

That will be slow the first time you call it for a component type, but quite fast thereafter, since it generates a simple IL method that does the cast et al.

Do you need to specify the value for the component too or do you just need a default component attached to the entity? If the latter, you can add a component to an entity using its ComponentType which you can get from System.Type.