You can use generics when defining your Recipe class, and constrain the generic type to the Food class, or classes derived from Food.
From the MSDN documentation:
When you define a generic class, you can apply restrictions to the
kinds of types that client code can use for type arguments when it
instantiates your class. If client code tries to instantiate your
class by using a type that is not allowed by a constraint, the result
is a compile-time error. These restrictions are called constraints.
Constraints are specified by using the where contextual keyword. The
following table lists the six types of constraints:
Further down in that article is a table that specifies how to achieve the result you want. In your case, your Recipe declaration will look like this:
public class Recipe<T> where T : Food
, which can define constructors as usual
new Recipe(params string[] ingredients)
notice there's no call to Bread.
When you instantiate Recipe, you can use var recipe = new Recipe<Bread>(ingredientsList)
.
If you try and declare the Recipe with something that doesn't derive from Food, you'll get an exception during design-time, which will inform you that
The type cannot be used as type parameter 'T' in generic
type of method 'Recipe'. There is no boxing conversion from
to 'Food'.
If you need help with generics, this MSDN article might be a good starting point.
UPDATE:
As per the comments, another way to implement this is to push the generic to a Create method.
Your code would look something like this:
public class Food { }
public class Bread :Food { }
public class Recipe
{
public T Create<T>() where T : Food, new()
{
return new T();
}
}
I've also added the new constraint (you need that in this case since passing a static class for instance would cause a runtime exception). You can now store a Recipe in a list, but now your logic will have to provide the specific type you want to invoke when the object is being created, rather when the recipe is being created.
If you want to determine the type at runtime (so basically store the type in the recipe for later creation add a constructor like thispublic Recipe(T typeToCreate)
and follow the methodology in this SO answer. This allows you to store the type.