You've got some answers explaining how to do this with an empty interface:
interface IMachineSomething {}
…
var m = new List<IMachineSomething>();
This works fine if all you want to put objects into that list. But what if you wanted to actually fetch objects from the list? What could you actually do with them, and what would the above solution force you to do?
The following shows that you can do even better with a non-empty interface.
IMachineSomething
is an empty interface. That is, if you actually want to do something with the objects in your list, all you're going to see of them is the empty contract defined by that interface. All the actual functionality resides with the concrete class
types. So you'd first have to check their type and then perform a type-cast in order to access the public fields:
foreach (IMachineSomething sth in m)
{
if (sth is MachineLine)
{
var machineLine = (MachineLine)sth;
machineLine.DoThis();
}
else if (sth is MachineCircle)
{
var machineCircle = (MachineCircle)sth;
machineCircle.DoThat();
}
else …
}
Since you're working with a object-oriented language, there is a much better solution: Polymorphism. That is, put common functionality (properties as well as methods) in the interface, so that you won't need to distinguish between the types when you go through your list:
interface IMachineSomething
{
void DoSomething();
}
class MachineLine : IMachineSomething
{
…
public void DoSomething() { DoThis(); } // example for implicit implementation, or…
}
class MachineCircle : IMachineSomething
{
…
void IMachineSomething.DoSomething() { DoThat(); } // …explicit implementation
}
Which allows you to get rid of the if (sth is …)
type checks and subsequent type-casts, and simplify your code to this:
foreach (IMachineSomething sth in m)
{
sth.DoSomething();
}
The loop no longer needs to care how each element gets processed exactly. All it needs to know that it must "do something" with an element, and the element itself will know what that means.
See also: