Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>It sounds like what you really want is a sum type. Although C# does not have these built in, there's a trick from functional programming that you can use called Church encoding to achieve this. It's completely type safe with no casts involved, however it's a bit weird to use in C# mostly due to the limitations of the type inference.</p> <p>The main trick is that instead of using properties and checks to retrieve one of the two alternatives, we have a higher order function <code>Map</code> that takes two functions as arguments and calls the appropriate one depending on which alternative was present. Here's how you would use it:</p> <pre><code>var stack = new Stack&lt;IEither&lt;Operator, Parenthesis&gt;&gt;(); stack.Push(new Left&lt;Operator, Parenthesis&gt;(new Operator())); stack.Push(new Right&lt;Operator, Parenthesis&gt;(new Parenthesis())); while (stack.Count &gt; 0) { stack.Pop().Map(op =&gt; Console.WriteLine("Found an operator: " + op), par =&gt; Console.WriteLine("Found a parenthesis: " + par)); } </code></pre> <p>Here's the implementation of <code>IEither</code>, <code>Left</code> and <code>Right</code>. They are fully generic and could be used anywhere you want a sum type.</p> <pre><code>public interface IEither&lt;TLeft, TRight&gt; { TResult Map&lt;TResult&gt;(Func&lt;TLeft, TResult&gt; onLeft, Func&lt;TRight, TResult&gt; onRight); void Map(Action&lt;TLeft&gt; onLeft, Action&lt;TRight&gt; onRight); } public sealed class Left&lt;TLeft, TRight&gt; : IEither&lt;TLeft, TRight&gt; { private readonly TLeft value; public Left(TLeft value) { this.value = value; } public TResult Map&lt;TResult&gt;(Func&lt;TLeft, TResult&gt; onLeft, Func&lt;TRight, TResult&gt; onRight) { return onLeft(value); } public void Map(Action&lt;TLeft&gt; onLeft, Action&lt;TRight&gt; onRight) { onLeft(value); } } public sealed class Right&lt;TLeft, TRight&gt; : IEither&lt;TLeft, TRight&gt; { private readonly TRight value; public Right(TRight value) { this.value = value; } public TResult Map&lt;TResult&gt;(Func&lt;TLeft, TResult&gt; onLeft, Func&lt;TRight, TResult&gt; onRight) { return onRight(value); } public void Map(Action&lt;TLeft&gt; onLeft, Action&lt;TRight&gt; onRight) { onRight(value); } } </code></pre> <hr> <p>References:</p> <ul> <li><a href="http://en.wikipedia.org/wiki/Tagged_union" rel="nofollow">Tagged union</a></li> <li><a href="http://en.wikipedia.org/wiki/Algebraic_data_type" rel="nofollow">Algebraic data type</a></li> <li><a href="http://en.wikipedia.org/wiki/Church_encoding" rel="nofollow">Church encoding</a></li> </ul>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

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