Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>A checked downcast, as used within Linq idioms, is perfectly safe.</p> <pre><code>foreach (Monkey m in myAnimals.OfType&lt;Monkey&gt;()) Program.FeedAnimal(m); </code></pre> <p>Or you could use the visitor pattern. The visitor object knows all the types of animal, so it has a <code>FeedAnimal</code> function for each. You pass the visitor object to an animal's <code>Feed</code> function, and it calls back to the correct <code>FeedAnimal</code> method, passing <code>this</code>.</p> <p>To make it extensible, you need a <code>Dictionary</code> of animal feeders:</p> <pre><code>private static Dictionary&lt;Type, Action&lt;Animal&gt;&gt; _feeders; </code></pre> <p>To register a feeding action, you'd do this to begin with:</p> <pre><code>_feeders[typeof(Monkey)] = a =&gt; { Monkey m = (Monkey)a; // give food to m somehow }; </code></pre> <p>But there's a downcast, and you have to give the correct type in the key as well. So make a helper:</p> <pre><code>public static void AddFeeder&lt;TAnimal&gt;(Action&lt;TAnimal&gt; feeder) where TAnimal : Animal { _feeders[typeof(TAnimal)] = a =&gt; feeder((TAnimal)a); } </code></pre> <p>This captures the pattern so you can reuse it completely safely:</p> <pre><code>AddFeeder&lt;Monkey&gt;(monkey =&gt; GiveBananasTo(monkey)); AddFeeder&lt;Dog&gt;(dog =&gt; ThrowBiscuitsAt(dog)); </code></pre> <p>Then when you need to feed an animal, use this extension method:</p> <pre><code>public static void Feed(this Animal a) { _feeders[a.GetType()](a); } </code></pre> <p>e.g.</p> <pre><code>a.Feed(); </code></pre> <p>So _feeders would be a private static field in the same static class as the extension method, along with the <code>AddFeeder</code> method.</p> <p><strong>Update:</strong> all the code in one place, also with support for inheritance:</p> <pre><code>public static class AnimalFeeding { private static Dictionary&lt;Type, Action&lt;Animal&gt;&gt; _feeders = new Dictionary&lt;Type, Action&lt;Animal&gt;&gt;(); public static void AddFeeder&lt;TAnimal&gt;(Action&lt;TAnimal&gt; feeder) where TAnimal : Animal { _feeders[typeof(TAnimal)] = a =&gt; feeder((TAnimal)a); } public static void Feed(this Animal a) { for (Type t = a.GetType(); t != null; t = t.BaseType) { Action&lt;Animal&gt; feeder; if (_feeders.TryGetValue(t, out feeder)) { feeder(a); return; } } throw new SystemException("No feeder found for " + a.GetType()); } } </code></pre> <p>You could also have a loop through the interfaces support by each type <code>t</code> - basically the same idea so I've kept the example simple here.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload