In terms of memory, the first way is going to cause an allocation every time, while the second will use a cached delegate object since it does not capture any variables. The compiler handles the generation of the cached delegate. There is no difference in the first case for capacity set to zero since the default constructor for List<T>
uses an empty array on initialization, the same as an explicit capacity of 0.
In terms of execution instructions, they are the same when the key is found since the second argument is not used. If the key is not found, the first way simply has to read a local variable while the second way will have a layer of indirection to invoke a delegate. Also, looking into the source code, it appears that GetOrAdd with the factory will do an additional lookup (via TryGetValue) to avoid invoking the factory. The delegate could also potentially be executed multiple times. GetOrAdd simply guarantees that you see one entry in the dictionary, not that the factory is invoked only once.
In summary, the first way might be more performant if the key is typically not found since the allocation needs to happen anyway and there is no indirection via a delegate. However if the key is typically found, the second way is more performant because there are fewer allocations. For an implementation in a cache, you typically expect there to be lots of hits so if that is where this is, I would recommend the second way. In practice, the difference between the two depends on how sensitive the overall application is to allocations in this code path.
Also whatever implementation that is using this will likely need to implement locking around the List<T>
that is returned since it is not thread-safe.