If you have a List where I is an interface and you add elements of type F1 and F2 where both implement the I interface, then when you retrieve any of the two elements from the List you can check the type of the reference using the keyword **is ** and proceed to apply the proper cast to the element you got from the List.
For example:
struct Foo1 : IFoo {...}
struct Foo2 : IFoo {...}
List<IFoo> listOfFoo = new List<IFoo>();
IFoo foo1 = new Foo1();
IFoo foo2 = new Foo2();
listOfFoo.Add(foo1);
listOfFoo.Add(foo2);
// lets retrieve the first element and check if it's a Foo1 value type
if(listOfFoo[0] is Foo1){
// cast element from List to Foo1
Foo1 foo = (Foo1) listOfFoo[0];
}
Since we're dealing with structs, when the element from the List gets casted back to the original value type, it should be be unboxed. But too many unboxing and boxing can hit performance and since you want to perform something like collision detection, that might bring you low performance.
Is it mandatory for you to use structs? Due to the boxing changes done to the variables might not behave properly if you perform operations on the boxed objects stored, and as I mentioned too much boxing might bring you poor results.
In my opinion a class with MemberwiseClone would be better.
You can read this article on MSDN that details the pros and cons for both structs and classes, this might help you understand better when to use one or the other.